GetItems() filtering Archived items - c#

Finding my around Xero API. Using the Xero .NetStandard library and getting a little stuck with what I thought would be quite a simple thing so pretty sure I'm missing something.
Trying to get a list of Items from a particular tenant using the follow code.
string whereFilter = "IsSold==True";
var xeroApi = new Xero.NetStandard.OAuth2.Api.AccountingApi();
var response = await xeroApi.GetItemsAsync(<AccessToken>, <TenantId>, null, whereFilter);
Where I'm getting stuck is I can't for the life of me figure out how to filter out items that have been marked as Archived. What am I missing?

Related

Microsoft Graph SDK Request Next Link of the Batch Response

I am using Microsoft Graph SDK to create a batch request that contains individual requests to request 20 different users. When I call GetNextLinkAsync() the result is always null. I have tried requesting 1000 different users using batch requests each containing 20 individual requests. This works fine, response is always returned in a single batch response.
I couldn't understand why the response is returned in single batch response content rather than giving me the link to fetch the next response?
Even though next link is null always, how can I follow it using Graph SDK? It is a string. It's not like next page request.
foreach (var batchRequest in batchRequests)
{
try
{
var responses = await PostBatchRequest(batchRequest.Request);
foreach (var id in batchRequest.RequestIds)
{
try
{
var user = await responses.GetResponseByIdAsync<User>(id);
users.Add(user.UserPrincipalName, user.Id);
} catch (ServiceException e)
{
logger.LogInformation(e.StatusCode);
}
}
} catch (ServiceException e)
{
logger.LogInformation(e.StatusCode);
}
}
I couldn't find proper documentation that tells you how to follow next link using Graph SDK or why it is always null for this type of requests, or are there any special type of requests for which next link is returned?
So a lot of this is framework stuff that's inside my wrapper classes, but the crux of the solution to your issue should be inside here:
var results = await batch.ParseAsync<ContactFolderContactsCollectionResponse, IContactFolderContactsCollectionPage>(response => {
var page = response.Value;
if (response?.AdditionalData != null && response.AdditionalData.ContainsKey("#odata.nextLink"))
{
page.InitializeNextPageRequest(Application.GraphConnection.Client, (string)response.AdditionalData["#odata.nextLink"]);
}
return page;
});
In this snippet I'm parsing out a ContactFolderContactsCollectionResponse from a batch with steps generated from a get request that would normally return a IContactFolderContactsCollectionPage. The ContactFolderContactsCollectionResponse is fetched by the wrapper internals using
GetResponseByIdAsync<ContactFolderContactsCollectionResponse>(id)
So it's pretty analogous to what you're doing except that there is probably some kind of UserResponse type that you should probably be using instead of User.
In my case the ContactFolderContactsCollectionResponse contains the IContactFolderContactsCollectionPage I actionally want in the Vvalue property hence:
var page = response.Value;
Now, IContactFolderContactsCollectionPage normally has a NextPageRequest property, but when you parse it directly from the ContactFolderContactsCollectionResponse, this is not filled out. Luckily, we can find the raw #odata.nextPage link in the ContactFolderContactsCollectionResponse's AdditionalData dictionary, and we can set it using the IContactFolderContactsCollectionPage.InitializeNextPageRequest methhod.
Hence the :
if (response?.AdditionalData != null && response.AdditionalData.ContainsKey("#odata.nextLink"))
{
page.InitializeNextPageRequest(Application.GraphConnection.Client, (string)response.AdditionalData["#odata.nextLink"]);
}
Hopefully that give you enough thread to pull on. Sorry if the rest of the syntax is confusing, as I said, a lot of it is operating in a wrapper framework I'm building and I
don't have time to build and test a clean solution.
It's also possible that the whole thing is different anyway on account of you having a batch with a thousand steps as opposed to a batch whose steps return thousands of objects like as in my case.
Either way, happy hunting.

How to download the picture of a Google+ user only if it has changed after a certain date?

I am using Google API to get information about an authenticated user. I can get the basic profile information, such as the ID and the full name. From the profile information, I can get the URL to the picture:
var plusMeUri = new Uri($"https://www.googleapis.com/plus/v1/people/me?key=<APP-ID>&access_token=<ACCESS-TOKEN>");
string userResponse = await HttpClient.GetStringAsync(plusMeUri);
JObject userObject = JObject.Parse(userResponse);
...
var imageObject = userObject.GetValue("image") as JObject;
var pictureUrl = imageObject.GetValue("url").Value<string>();
var pictureUri = new Uri(pictureUrl);
string uri = $"{pictureUri.Scheme}://{pictureUri.Host}{pictureUri.AbsolutePath}";
var pictureRequest = new HttpRequestMessage(HttpMethod.Get, uri);
pictureRequest.Headers.IfModifiedSince = <previous-timestamp>;
HttpResponseMessage pictureResponse = await HttpClient.SendAsync(pictureRequest);
if (pictureResponse.StatusCode == HttpStatusCode.NotModified)
// No need to handle anything else
return;
Question
I do not want to download the user's picture if it has not changed. This is why I am using the IfModifiedSince property. It does work with Facebook's API but it does not seem to work with Google's. How can I make it work?
From the information given, it seems like what you're trying to do is determine whether the image you're downloading/about to download is the same image as you've downloaded before. After looking at the Google+ API docs, it looks like the header you've been using isn't officially (at least not obviously) supported by their APIs.
But this is not the only way we can determine whether the image has changed or not (in fact, date last modified isn't necessarily the best way to do this anyway). Alternative methods include:
1) diffing the two images
2) checking the url (if we can assume different resources have different urls)
1 is likely the most accurate but also likely the least efficient, so I'll leave that to you to solve if you decide to go that route. I think the most promising is #2. I went ahead and played around with the API a little bit and it looks like the image.url field changes when you update your profile picture.
For example, here are my last two Google+ profile picture URLs:
https://lh4.googleusercontent.com/-oaUVPGFNkV8/AAAAAAAAAAI/AAAAAAAAAqs/KM7H8ZIFuxk/photo.jpg?sz=50
https://lh4.googleusercontent.com/-oaUVPGFNkV8/AAAAAAAAAAI/AAAAAAAAl24/yHU99opjgN4/photo.jpg?sz=50
As such, instead of waiting for the response from the server and checking its header to decide whether the image has been updated or not, you may be able to short-circuit the entire HTTP request by simply checking whether the last image you pulled down was from the same url or not. If it was from the same URL, it's likely you've already acquired that image otherwise you may not have it so should incur the cost of downloading anyway.
In this case, your code would read something like:
var imageObject = userObject.GetValue("image") as JObject;
var pictureUrl = imageObject.GetValue("url").Value<string>();
if(pictureUrl != <previous-picture-url>)
{
// insert get new picture logic here...
}

How to work with the "eBay finding APi"

I`m relatively new to programming and I´m completely new to Stack overflow, so please be patient with me! Currently I work on a ASP.NET MVC project including the Ebay finding API.
The goal i want to accomplish is to create a Website on which you can search for different articles on Ebay and being able to use certain filters using the Ebay finding API. This is a training projekt for me, as the C# part of the whole thing is a good practice in my opinion. Unfortunately I´m stuck with the whole API connection to ebay part and havent done any C# programming myself.
Frankly i have no idea what im doing and I hope some of you may have an idea or some tips for me. I know I might be vague and I´m sorry, but i´m just at the beginning of programming.
What have i done so far?
I already registered on the ebay developers program and I already have my App ID, the Dev IDm the Cert ID and a Token.
Important: I currently only work with the sandbox!
I found a piece of code online which I´m using, but now im stuck. Obisously i filled in the IDs and the token but deleted it for this post. In the "Index" class at the end of my piece of code I entered the ID of a random Ebay article for testing purposes. When i debug I get this Exception:
"eBay.Service.Core.Sdk.ApiException: 'This item cannot be accessed because the listing has been deleted, is a Half.com listing, or you are not the seller."
I would really appreciate if someone can show me how to do it correctly or push me in the right direction. I have to admit that i find the whole Ebay API documentation etc. to be very confusing and I dind´t find any advice on how to start. I take any advice you guys can give me!
Here is the code I found and used so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Windows.Forms;
using System.Resources;
using eBay.Service.Call;
using eBay.Service.Core.Sdk;
using eBay.Service.Core.Soap;
namespace Ebay_API_Neu.Controllers
{
public class HomeController : Controller
{
public GetItemCall getItemDataFromEbay(String itemId)
{
ApiContext oContext = new ApiContext();
oContext.ApiCredential.ApiAccount.Developer = "//dev ID"; // use your dev ID
oContext.ApiCredential.ApiAccount.Application = "//App ID"; // use your app ID
oContext.ApiCredential.ApiAccount.Certificate = "//cert ID"; // use your cert ID
oContext.ApiCredential.eBayToken = "//Token"; //set the AuthToken
oContext.SoapApiServerUrl = "https://api.sandbox.ebay.com/wsapi";
//set the Site of the Context
oContext.Site = eBay.Service.Core.Soap.SiteCodeType.Germany;
//the WSDL Version used for this SDK build
oContext.Version = "735";
//very important, let's setup the logging
ApiLogManager oLogManager = new ApiLogManager();
oLogManager.ApiLoggerList.Add(new eBay.Service.Util.FileLogger("GetItem.log", true, true, true));
oLogManager.EnableLogging = true;
oContext.ApiLogManager = oLogManager;
GetItemCall oGetItemCall = new GetItemCall(oContext);
//' set the Version used in the call
oGetItemCall.Version = oContext.Version;
//' set the Site of the call
oGetItemCall.Site = oContext.Site;
//' enable the compression feature
oGetItemCall.EnableCompression = true;
oGetItemCall.DetailLevelList.Add(eBay.Service.Core.Soap.DetailLevelCodeType.ReturnAll);
oGetItemCall.ItemID = itemId;
try
{
oGetItemCall.GetItem(oGetItemCall.ItemID);
}
catch (Exception E)
{
Console.Write(E.ToString());
oGetItemCall.GetItem(itemId);
}
GC.Collect();
return oGetItemCall;
}
public ActionResult Index()
{
getItemDataFromEbay("173354849991");
return View();
}
From the error you are getting I would guess that you are trying to get information regarding a "random listing" you have not entered yourself on the eBay sandbox. In order to use GetItem the listing you are retrieving has to have been created using your sandbox user id.
Take a look at the below link to API doc for GetItem() - specifically the requirements for "Testing GetItem". If you think I might be correct then try creating a listing in the sandbox using either the Web Interface or eBay API AddItem() before retrieving it with GetItem().
https://developer.ebay.com/devzone/xml/docs/reference/ebay/getitem.html

VersionOne: Getting message that VersionOneAPIConnector is obsolete and I should use V1Connector instead. But how?

I am trying to upgrade my c# programs to VersionOne.SDK.API version 15.3.0.0. I am getting a message that VersionOneAPIConnector is obsolete and that I should use V1Connector instead. When the ObjectModel API was discontinued, I had changed to doing everything with VersionOneAPIConnector using query.v1 (using HttpPost) and rest-1.v1/Data(using SendData). After getting the new version, I figured out how to use V1Connector and pass it to Services and then to use ExecutePassThroughQuery() to pass what had been the 2nd argument to HttpPost for my query.v1 code like this:
Original code:
Stream resultStream = _cx.HttpPost("/query.v1", System.Text.Encoding.UTF8.GetBytes(GetQueryForMembers()));
using (StreamReader reader = new StreamReader(resultStream, Encoding.UTF8))
{
result = reader.ReadToEnd();
}
New Code:
result = _service.ExecutePassThroughQuery(GetQueryForMembers());
Where GetQueryforMembers() is:
public static string GetQueryForMembers()
{
return #"
from: Member
select:
- Email
where:
AssetState: Active";
}
But, I can't figure out how to use V1Connector/IServices for my rest/SendData code. All the Rest examples on the VersionOne site now show using it from the API Console, not from stand-alone code. It looks like at least some of the things I was doing with Rest can be done via Services.executeOperation() or Services.Meta, but the V1 employee that I was working with to get rid of my Object Model code a few years ago had recommended only using the API for the connection and to otherwise use Rest and Query, so that I didn't have to worry about compatibility with .NET versions. But, from looking at the examples currently provided and the functionality available on the V1Connector/IServices classes, it looks like maybe V1 wants us to use Meta API rather than REST now? Or is there a way to use REST directly that I am missing? From looking at the source, I see there is an internal UseDataAPI() on the V1Connector that IServices uses. But, it only uses it in Save, ExecuteOperation and Retrieve and it doesn't look like any of those do what I'm trying to do.
This is an example, if what I was doing before with REST (where _passed_cx is a VersionOneAPIConnector)
string newDefect = string.Concat("<Asset href=\"/MentorG01/rest-1.v1/New/Defect\">",
"<Attribute name=\"Name\" act=\"set\">", cdata_attribute_value, "</Attribute>",
"<Relation name=\"Scope\" act=\"set\">",
"<Asset href=\"/MentorG01/rest-1.v1/Data/Scope/", project_oid.Split(':')[1], "\" idref=\"", project_oid, "\" />",
"</Relation>",
"</Asset>");
string url = "rest-1.v1/Data/Defect";
Stream resultStream = _passed_cx.SendData(url, newDefect);
Anyone know how to use rest-1.v1 with V1Connector? If so, can you provide an example?

Is there a more efficient way to deal with Amazon Product advertising API on C# ASP.NET (esp MVC 5)?

I have finally got the Amazon product advertising API to work on my MVC 5 site. I am using the "SignedRequestHelper" class that was provided on one of the downloads from the Amazon site. I have actually got a ref to the Amazon API but I do not seem to be using it at all at present.
What I am using so far is (controller):
SignedRequestHelper helper = new SignedRequestHelper("myAWSaccessKeyID",
"mysecretKey", "webservices.amazon.co.uk");
Dictionary<String, String> items = new Dictionary<String, String>();
items.Add("Service", "AWSECommerceService");
items.Add("Operation", "ItemSearch");
items.Add("AWSAccessKeyId", "myAWSaccessKeyID");
items.Add("AssociateTag", "myTag");
items.Add("SearchIndex", SearchIndex);//This is a string value (selectbox)
items.Add("ResponseGroup", "Images,ItemAttributes,OfferFull,Offers,OfferSummary,Reviews");
items.Add("Keywords", keyword);//This is a string value
string requestUrl = helper.Sign(items);
ViewBag.Stuff = requestUrl;//Just so I could see the whole URL!
WebRequest request = HttpWebRequest.Create(requestUrl);
WebResponse response = request.GetResponse();
XmlDocument doc = new XmlDocument();
doc.Load(response.GetResponseStream());
XmlNodeList titleNodes = doc.GetElementsByTagName("Item");
ViewBag.Titles = titleNodes;
You may notice I partially the copied the style of JAVA code from the scratch pad.
From that point on in the view I just deal with each part as it comes. It is kind of messy and horrid and dealing with switches like this:
foreach (System.Xml.XmlNode item in ViewBag.Titles)
{
<h3>Item: #count</h3>
foreach (System.Xml.XmlNode child in item.ChildNodes)
{
switch (child.Name)
{
case "ASIN":
<p>ASIN: #child.InnerText</p>
break;
case "MediumImage":
<img src="#child.ChildNodes[0].InnerText" />
break;
case "ItemAttributes":
foreach (System.Xml.XmlNode child1 in child.ChildNodes)
{
if(child1.Name == "Title")
{
<p>#child1.InnerText</p>
}
}
break;
}
}
count++;
}
It works and I can use the XML document etc. I just need to know if there is a way to change it so that it is actually using the API part that was given as a reference. I would rather use proper tools than do it with raw XML like this. I had such difficulty connecting with the Amazon documentation that I basically just tried to connect in the JAVA style code on Amazon's scratchpad.
You can use the following nuget Nager.AmazonProductAdvertising package.
PM> Install-Package Nager.AmazonProductAdvertising
Example Controller
public ActionResult ProductSearch(string search)
{
var authentication = new AmazonAuthentication();
authentication.AccessKey = "accesskey";
authentication.SecretKey = "secretkey";
var wrapper = new AmazonWrapper(authentication, AmazonEndpoint.DE);
var result = wrapper.Search(search);
return View(result);
}
Example View
#model Nager.AmazonProductAdvertising.Model.AmazonItemResponse
#{
ViewBag.Title = "Search";
}
<table class="table">
<tr>
<th>ASIN</th>
<th>SalesRank</th>
</tr>
#foreach (var item in Model.Items.Item)
{
<tr>
<td>#item.ASIN</td>
<td>#item.SalesRank</td>
</tr>
}
</table>
Take a look to AWS SDK for .Net. Also you can find some guides and how to work with it's APIs.
The AWS SDK for .NET includes the following:
The current version of the AWS SDK for .NET.
All previous major versions of the AWS SDK for .NET.
Sample code that demonstrates how to use the AWS SDK for .NET with several AWS services.
There is a library that is incredibly thorough for dealing with the Amazon Product Advertising API (PAAPI). When you make a request, you can receive a variety of responses, but this library can handle them all! It reads the XML and puts all the information in an object.
I'm working on two MVC 5 sites right now that interact with the PAAPI. I have a separate folder with the files and a couple files I wrote to make requests and process responses by pulling the data I need out of the object created by the library.
I made a C# console app demo, and you can view it here:
https://github.com/zoenberger/AmazonProductAdvertising
I used this for guidance:
https://flyingpies.wordpress.com/2009/08/01/17/
However, I ran into a couple errors:
In some instances, large responses require you to modify the
MaxReceivedMessageSize and is show on the demo.
I ran into an error with the ImageSets[] in the library. May people have and the fix is here.
I believe that I have finally found a way to use the actual Amazon Prod Adv API now. The problem was working out how to sign the request using the latest API (that I had added as a reference). The reference was added in a similar way to the getting started guide even though that was making reference to VS2005. That is obviously 10 years old but I somehow did get it working with a bit of problem solving. I just never got the signing correct so I ended up using that horrid REST bodge (in my original question)!
The post that has helped me now is this one:
amazon product advertising api - item lookup request working example
It is the one marked as the answer. It has only 4 up-votes but it is the best thing I have found. I put all the classes into the controller to test it but I will now have to do it properly using models or extension classes. It worked anyway though.

Categories