Skip to content
July 23, 2012 / rivdiv

Amazon Reports API C# Integration

In a previous post I’ve shown how to to submit a feed using the Amazon Feeds API. In this post I’m going to show how to download a report from Amazon using the Reports API. Download the API from the Amazon Developer Home page.

Before we actually download the report, Amazon requires us to submit a request. The time we need to wait after the request until we can download the report varies based on the report type and possibly other factors.

Below are 2 examples of report types:

  • _GET_MERCHANT_LISTINGS_DATA_ – download all inventory.
  • _GET_FLAT_FILE_ORDERS_DATA_ – download orders from specified date.

For readability, I created an Report Type enum, with these report type values, which will be used as part of the argument of the below method. This method requests the report.

public RequestReportResult GetRequestReportResult(ReportType reportType)
{
    RequestReportRequest reportRequestRequest = new RequestReportRequest();
    reportRequestRequest.Merchant = Merchant;
    reportRequestRequest.ReportType = reportType.ToString();

    // If this is an order report, get only last week
    if (reportType == ReportType._GET_FLAT_FILE_ORDERS_DATA_)
    {
        reportRequestRequest.StartDate = DateTime.Now.AddDays(-7);
    }

    return GetClient().RequestReport(reportRequestRequest).RequestReportResult;
}

The GetClient method used here returns a MarketplaceWebServiceClient object. Refer to my previous Amazon post for the code. Also, notice that in the case of a request for an order report, we are setting the StartDate property to specify the date from which we want orders downloaded.

Now we can use this method to get a list of the requests and their statuses:

private List<ReportRequestInfo> GetReportRequests()
{
    GetReportRequestListRequest reportlistReqests = new GetReportRequestListRequest();
    reportlistReqests.Merchant = Merchant;
    GetReportRequestListResponse reportlistResponse = GetClient().GetReportRequestList(reportlistReqests);
    return reportlistResponse.GetReportRequestListResult.ReportRequestInfo;
}

Once the status of our request is _DONE_, we can go ahead and download the report. The data will be saved to a text file. From there you can do whatever you want with it, like import it into your DB.

Here’s the method to download the report. It takes in a RequestReportInfo object (which you get from the GetReportRequests method):

private FileInfo GetReportFile(ReportRequestInfo reportInfo)
{
    GetReportRequest reportRequest = new GetReportRequest();
    reportRequest.Merchant = Merchant;
    reportRequest.WithReportId(reportInfo.GeneratedReportId);

    GetReportResponse reportResponse = new GetReportResponse();

    string path = HttpContext.Current.Server.MapPath("~/Files/Report-" + reportInfo.ReportType + "-" + reportInfo.GeneratedReportId + ".txt");

    using (FileStream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
    {
        reportRequest.Report = stream;
        reportResponse = GetClient().GetReport(reportRequest);
    }

    return new FileInfo(path);
}

That’s it! Again, there isn’t much documentation on this so I hope this post is found helpful.

Happy Coding!

July 5, 2012 / rivdiv

Amazon Feeds API C# Integration

I’m in the process of building an application which requires strong integration with the Amazon API. I needed to submit product feeds, update inventory and prices, as well as downloading reports and couple other things. When I first was given the project, of course the first I did was a quick google search to see what kind of documentation is out there on the API. There was some info out there (links below), but I had to do a lot playing around first with bits of google searches to get what I needed.

In hopes of making this easier for other Amazon API developers, I’ll outline the basic process for a feed submission and some methods that I’ve ended up integrating into my application using the Amazon Feeds API.

Here’s a few FeedTypes I’ve used.

  • _POST_INVENTORY_AVAILABILITY_DATA_ – update inventory.
  • _POST_PRODUCT_PRICING_DATA_ – update pricing.
  • _POST_PRODUCT_DATA_ – add products to listing.
  • _POST_PRODUCT_OVERRIDES_DATA_ – override info, such as shipping costs.

To get started, you’ll need your Amazon MarketPlaceId, Merchant, Access Key and Secret Access Key, and of course the actual Feeds API.

Note, in the examples posted below, there’s a method called GetClient() which is used. It returns a MarketplaceWebserviceClient object. Looks like this:

private MarketplaceWebServiceClient GetClient()
{
    MarketplaceWebServiceConfig mwsConfig = new MarketplaceWebServiceConfig();
    mwsConfig.ServiceURL = "https://mws.amazonservices.com";
    mwsConfig.SetUserAgentHeader("YourCompany", "1.0", "C#", new string[] { });

    return new MarketplaceWebServiceClient(AccessKey, SecretAccessKey, mwsConfig);
}

I’ve created a generic method to submit all feeds, which goes like this:

public SubmitFeedResult SubmitFeed(FileInfo file, FeedType feedType)
{
    SubmitFeedResponse response = new SubmitFeedResponse();

    SubmitFeedRequest sfrequest = new SubmitFeedRequest();
    sfrequest.Merchant = Merchant;
    sfrequest.MarketplaceIdList = MarketPlaceID;

    using (FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.ReadWrite))
    {
        sfrequest.FeedContent = stream;
        sfrequest.ContentMD5 = MarketplaceWebServiceClient.CalculateContentMD5(sfrequest.FeedContent);
        sfrequest.FeedContent.Position = 0;
        sfrequest.FeedType = feedType.ToString();

        response = GetClient().SubmitFeed(sfrequest);
    }

    return response.SubmitFeedResult;
}

I pass in the file which contains the XML to submit, along with an FeedType enum I’ve declared, which contains my FeedTypes listed above.

Once you submit a feed, you’d want to see the status. Did it go through, were there any errors/warnings etc.

There’s a FeedSubmissionInfo object that returns info for a specific submission. I use this method to return a list of feed submissions.

public List<FeedSubmissionInfo> GetFeedSubmissionList()
{
    GetFeedSubmissionListRequest request = new GetFeedSubmissionListRequest();
    request.Merchant = Merchant;
    GetFeedSubmissionListResponse response = GetClient().GetFeedSubmissionList(request);
    return response.GetFeedSubmissionListResult.FeedSubmissionInfo;
}

You can now get one FeedSubmissionID from one of the FeedSubmissionInfo objects returned, and pass it in to the following method, which will create and return a FileInfo containing the response. You can further modify this to parse out the XML and reformat the text so it’s readable. Change the path to your preferred location for the file to be created to.

public FileInfo GetFeedSubmissionResultFile(string feedSubmissionID)
{
    GetFeedSubmissionResultRequest request = new GetFeedSubmissionResultRequest();
    request.FeedSubmissionId = feedSubmissionID;
    request.Merchant = Merchant;

    GetFeedSubmissionResultResponse response;

    string path = HttpContext.Current.Server.MapPath("~/Files/SubmissionResult-" + feedSubmissionID + ".txt);

    using (FileStream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
    {
        request.FeedSubmissionResult = stream;
        response = GetClient().GetFeedSubmissionResult(request);
    }

    return new FileInfo(path);
}

That’s the basic process of a feed submission using the Amazon Feed API. You can do plenty more with  the Amazon APIs, like managing orders, prices, inventory, and shipping.

Here are some useful links:

Amazon Developer Home page

XML Documentation

Community Forums

Hope this helps!

June 15, 2012 / rivdiv

Proxy & 504 Response From Server

I had a program which pulled custom-defined data that the user has set and populated a text file with it and uploaded it to an FTP. There were instances where the server would throw a 504 error. I was able to see this with Fiddler – I usually have that open when I program ASP.NET so I can see what’s going on.

The first thing that came to mind was server timing out. I wasn’t exactly sure if this was an ASP.NET page timeout issue or a SQL Server timeout. I extended the CommandTimeout on the SqlCommand and the ExecutionTimeout on the HttpRuntime tag in the web.config. Both didn’t seem to help – I was still getting the 504 response.

All along, I was under the impression that the data wasn’t being returned and that the text file wasn’t being generated. I implemented some logs to see where the code reached and was surprised to find that it had returned the DataTable and generated the file.

At that point, I was a bit confused and googled around for some info that would tell me why a server would return a 504. Google returned some links that were related to 504 and proxies.

That gave me the idea to check my proxy settings.

And… the checkbox was checked. I unchecked it and no more 504 responses.

I don’t know enough about servers and proxies to understand how and why it made a difference, but I maybe this will help others who come across this same problem.

(As a side point, I wonder if the proxy was actually Fiddler’s proxy. Now, that would be ironic.)

Happy coding!

June 13, 2012 / rivdiv

Uploading a File Using ASP.NET Web API RC

In this post I’m going show an example of uploading a file into a directory on the server using ASP.NET Web API RC. You can download the package from NuGet or MVC 4 from the ASP.NET site.

To begin, add a new ASP.NET MVC 4 Project, and select Web API as the project template. Add a new View (or modify an existing one) to contain the following HTML.

<h2>

Upload a File</h2>

<p>

    File to Upload:<br />

    <form enctype=”multipart/form-data”>

    <input id=”fileinput1″ type=”file” name=”file” />

    </form>

</p>

<p>

    New File Name:<br />

    <input type=”text” id=”txtNewFileName” />

</p>

<p>

    Folder to save in:<br />

    <select id=”ddlFolders”></select>

</p>

<p>

    <input type=”button” id=”btnUpload” value=”Upload” onclick=”upload()” />

</p>

    <div id=”divResult” />

We need to populate the dropdown with the directories on our server. Of course, we’ll use Web API for that.

Add a new Web API Controller Class to your solution and name it FilesController.cs. Add a new Action, called GetDirectories().

public List<string> GetDirectories()

{

    var directories = new List<string>();

    Directory.GetDirectories(HttpContext.Current.Server.MapPath(“~/”)).ToList().ForEach(d => directories.Add((new DirectoryInfo(d)).Name));

    return new List<string>(directories);

}

We’ll use jQuery to get the Response. Make sure you have your jQuery script references, and add the following jQuery code, which will loop through the directory names  and add each one to the drop down.

<script type=”text/javascript”>

    $(document).ready(function () {

        $.getJSON(“api/files/getdirectories,

                    function (data) {

                        var items;

                        $.each(data, function (key, val) {

                            items += “<option value=’” + val + “‘>” + val + “</option>”;

                        });

                        $(‘#ddlFolders’).html(items);

                    });

   });

</script>

Hit F5 to run your application. Notice the DropDown populated with the directories. If you take a look in Fiddler, you should be able to see the GetDirectories() action being hit, with the JSON string values being returned.

Fiddler View

The last step is to POST the file to the Web API and save it in the selected directory as the specified file name.

It actually  pays to give the user the option to rename the file, as in RC, the file is saved as a random string such as “BodyPart_10cfd996-ff7b-46e2-b0a4-dae46abbe765″. See my question on SO, to which Henrik F. Nielsen and Filip W. thankfully responded. (Follow them on twitter for great Web API info/updates.) You would want to rename the file either way with the correct extension.

Here’s the UploadFile Action, which takes in two parameters named “folder” and “newFileName” that will be coming from the URI.

public Task<HttpResponseMessage> UploadFile([FromUri]string folder, [FromUri]string newFileName)

{

if (!Request.Content.IsMimeMultipartContent())

{

throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.UnsupportedMediaType));

}


// Save file

string path = HttpContext.Current.Server.MapPath(string.Format(“~/{0}”, folder));

MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(path);

var task = Request.Content.ReadAsMultipartAsync(provider);


// Log exceptions

task.ContinueWith(t =>

{

if (t.IsFaulted)

{

// Log t.Exception

}

});


return
task.ContinueWith<HttpResponseMessage>(t =>

{

var bodyPart = provider.BodyPartFileNames.FirstOrDefault();

string savedFile = bodyPart.Value;

string originalFile = bodyPart.Key.TrimStart(‘”‘).TrimEnd(‘”‘);

string newFile = string.Format(“{0}{1}”, newFileNamePath.GetExtension(originalFile));


// Copy file and rename with new file name and correct extension

        FileInfo file = new FileInfo(savedFile);

        file.CopyTo(Path.Combine(path, newFile), true);

        file.Delete();


// Return ResponseMessage

         return new HttpResponseMessage()

{

Content = new StringContent(string.Format(“File saved in {0} as {1}.”, folder, newFile))

};

}, TaskScheduler.FromCurrentSynchronizationContext());

}

To call the UploadAction, add the following jQuery button click function.

$(‘#btnUpload’).click(function () {

    $(“#divResult”).html(“Uploading…”);

    var formData = new FormData($(‘form’)[0]);

    $.ajax({ url: ‘api/files/uploadfile?folder=’ + $(‘#ddlFolders’).val() + ‘&newfileName=’ + $(‘#txtNewFileName’).val(),

        type: ‘POST’,

        success: function (data) {

            $(“#divResult”).html(data);

        },

        data: formData,

        cache: false,

        contentType: false,

        processData: false

    });

});

Here we’re calling UploadFile(), passing along the folder and newFileName. The div will show “Uploading…”, and upon a successful response, it will display where the file has been saved. Again, fiddler would show you the request and response details.

*Note, I’m using the FormData element here, which is currently not supported in IE (9) (and, if I’m not mistaken, Opera). An alternative would be post the form with the jQuery Form Plugin

You can now run your application and try it out! You should be able to see the file in your directory.

Uploading a file

File in directory

I hope this post helps other Web API beginners who like me are just starting to play around with it. Comments are welcome, and thanks for reading!

May 31, 2012 / rivdiv

Referencing Controls in Web Forms Data Controls

I’ve found that quite a few questions in the Web Forms Data Controls section of the ASP.NET forums are related to finding controls in various data controls, including the GridView, ListView, Repeater, DataList, FormView and DetailsView. Figured I’ll write up a basic post to serve as a pointer.

To find any control in a multi-record control, we first need to get a reference to the row or item that the control we’d like to access is in. Once we have a reference to the row or item, we’ll use the FindControl method, passing in the ID of the control.

Below is some sample code based on a Button and Label in the ItemTemplate. Our goal is to get a reference to the Label in all instances.

GridView

RowCommand Event:

Button Button1 = (Button)e.CommandSource;

GridViewRow row = (GridViewRow)Button1.NamingContainer;

Label Label1 = (Label)row.FindControl(“Label1″);

RowDatabound Event:

if (e.Row.RowType == DataControlRowType.DataRow)

{

    Label Label = (Label)e.Row.FindControl(“Label1″);

}

Repeater, DataList

ItemCommand Event:

Label Label1 = (Label)e.Item.FindControl(“Label”);

ItemDataBound Event:

if (e.Item.ItemType == ListItemType.Item

    || e.Item.ItemType == ListItemType.AlternatingItem)

{

    Label Label1 = (Label)e.Item.FindControl(“Label1″);

}

ListView

ItemCommand Event: Same as Repeater, DataList

ItemDataBound Event:

if (e.Item.ItemType == ListViewItemType.DataItem)

{

    Label Label = (Label)e.Item.FindControl(“Label1″);

}

DetailsView, FormView

We can use the FindControl method directly off the DetailsView or FormView, since it’s a single record control.

Label Label = (Label)DetailsView1.FindControl(“Label1″);

In all instances, we can access the Label on any of the Button’s events, by casting the sender to Button and using FindControl on its NamingContainer.

Hope this helps.

May 15, 2012 / rivdiv

Hello world!

Welcome to my blog! This is my very first post, and I hope there will be many more. I plan on using this blog to share thoughts and ideas that I find interesting on .NET programming.

Bye for now. Happy coding!

Follow

Get every new post delivered to your Inbox.