Using Force.com for arbitrary REST API methods - c#

NB: This is a duplicate of my question on https://github.com/developerforce/Force.com-Toolkit-for-NET/issues/357. I'll sync both threads after this is resolved.
I'm using the Force.com toolkit for .NET. SOQL queries are working fine for me, but I'm trying to also make a simple REST call similar to one I can make with the REST Explorer tool at https://workbench.developerforce.com/restExplorer.php.
My code is:
using (var queryClient = new ForceClient(authClient.InstanceUrl, authClient.AccessToken, authClient.ApiVersion))
{
// Works fine
string soql = GetMyQuery();
QueryResult<dynamic> result = await queryClient.QueryAsync<dynamic>(soql);
// Throws exception. Changing version # doesn't seem to have any effect.
dynamic restResult = await queryClient.ExecuteRestApiAsync<dynamic>("/services/data/v46.0/sobjects/Task/describe");
When I get to ExecuteRestApiAsync, I get the exception:
Salesforce.Common.ForceException
HResult=0x80131500
Message=Could not find a match for URL
Source=Salesforce.Common
StackTrace:
at Salesforce.Common.JsonHttpClient.<HttpGetAsync>d__4`1.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
[...]
I assume that my argument "/services/data/v46.0/sobjects/Task/describe", which works fine in the REST Explorer tool, needs to change. But I've guessed a bunch of different options (different versions, with or without leading URL string, etc.) and so far haven't gotten anything to work.
Can someone tell me how to use ForceClient to get the same results I get back from the Salesforce Workbench REST Explorer?

I ended up looking more closely at the ForceClient code. ExecuteRestApiAsync was not the correct call for this. For my specific example, there are 3 ways I found that work:
dynamic restResult = await queryClient.DescribeAsync<dynamic>("Task");
restResult = await queryClient.BasicInformationAsync<dynamic>("Task/describe/");
restResult = await queryClient.BasicInformationAsync<dynamic>("Task/describe");
(All 3 of the above lines return the same result)
This will work fine for sobjects. I don't think it's currently possible to use this library directly for things like reports which use "analytics" in their REST API definitions, but there are a couple workarounds that don't require recompiling the code. The cleanest and most performant of these that I've found is to pass your own HttpClient instances into the ForceClient ctor and use those directly instead of the methods on the ForceClient. An inspection of the ForceClient code will reveal that most of these methods are just thin string.Format() wrappers on HttpClient methods anyway.

Related

Getting started with soap web service client c#

My boss asked how long it would take to build a client to access a web service that will send and receive some basic data and embedded documents. Just starting playing with it to see what's involved. I have been doing web and desktop development for about 20 years but have literally never touched a web service so with that I'm at the extreme newb level.
So far I used the wsdl to create the ServiceReference1 and I can see the methods in intellisense but I don't have the first clue where to start with calling the methods, passing parameters and consuming the response. I feel stupid because I'm sure it's pretty simple but just flailing at the code and looking for on point examples has gotten me nowhere. Usually I can find something through google in minutes that is exactly on point but not having luck here. Would appreciate a push in the right direction.
So basic questions. Proper way to make the calls. How and where to land the returned data. How to add parameters.
Here is my first attempt. This gets a simple list and has no parameters. The result in fiddler returns data but there is a runtime type mismatch error which I think is caused by some stray characters leading the response which appear to be caused by chucking, what ever that is. The response starts with 1ffs every time then contains the remainder of the xml. Secondarily I need to get the list into a dataset or some other container but I was hoping to just be able to step into the code and see a result
ServiceReference1.FilingInfoClient webservice = new FilingInfoClient();
ServiceReference1.courtListRequest cr = new ServiceReference1.courtListRequest();
ServiceReference1.courtListResponse lr = new ServiceReference1.courtListResponse();
lr = webservice .getCourtList(cr);
This is essentially the same but takes a date param. When I run this fiddler shows the parameter is not being sent. No other errors but I'm sure only because it exploded immediately.
ServiceReference1.FilingInfoClient webservice = new FilingInfoClient();
ServiceReference1.messageListRequest mr = new ServiceReference1.messageListRequest();
ServiceReference1.MessageListResponse mlr = new ServiceReference1.MessageListResponse();
mr.latestMessagePullTimestamp = DateTime.Now.AddDays(-5);
mr.endTimestamp = DateTime.Now;
mlr.latestMessagePullTimestamp = DateTime.Now;
mlr = webservice.getMessageList(mr);
This is the info provided by the web service host
<x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:urn1="urn:green:partner:ws:schema:FilingInfo">
<x:Header/>
<x:Body>
<urn1:getcourtList>
<urn1:courtListRequest/>
</urn1:getcourtList>
</x:Body>
</x:Envelope>
<x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:urn1="urn:green:partner:ws:schema:FilingInfo">
<x:Header/>
<x:Body>
<urn1:getMessageList>
<urn1:messageListRequest>
<urn1:latestMessagePullTimestamp>?</urn1:latestMessagePullTimestamp>
</urn1:messageListRequest>
</urn1:getMessageList>
</x:Body>
</x:Envelope>
we've got request and response pairs for each operation in the webservice. think like request => input, response => output, operation => method.
the webservice is an API. things that consume APIs are clients. the WSDL describes the API's operations and their requests and responses. tools like visual studio know how to read WSDLs and build C# code to perform those (SOAP) operations under-the-hood. this is the client (here FilingInfoClient). visual studio'll also generate classes representing each request and response.
this allows for a familiar programming experience. you call a method, give it some input, and it returns some output.
using (var client = new FilingInfoClient())
{
var request = new courtListRequest
{
//TODO fill in relevant properties
};
var response = client.getCourtList(request);
}

C# AmazonDeviceFarmClient ListDevicesAsync not returning full list of devices

We use the AmazonDeviceFarmClient.ListDevicesAsync call with a very simple ListDevicesRequest in order to get a list of all devices available in Device Farms in a C# platform.
An example of our code:
var cfg = new AmazonDeviceFarmConfig
{
RegionEndpoint = RegionEndpoint.USWest2
};
using (var client = new AmazonDeviceFarmClient(new BasicAWSCredentials([DeviceFarmAccessKey], [DeviceFarmSecretKey]), cfg))
{
var arn = GetProjectArn();
var response = client.ListDevicesAsync(new ListDevicesRequest
{
Arn = arn
}).Result;
}
On Powershell/python, using the aws devicefarm list-devices command, a comprehensive list of all possible devices is returned.
Using our C# code we get a truncated list, missing several devices that we need, despite there being no filters. We have tried various things including changing the permissions of the API user, and changing the region with no luck.
It looks increasingly like our best course of action will be to run a powershell script within our C# environment, rather than using the C# Device Farm API, whose list devices command appears to be not working.
Given that we are waiting for a result using the Result keyword, I would not expect this to be an async issue.
As pointed out by Jeroen Mostert, we missed out on the NextToken property. It was sending an incomplete list down (an uneven number, like 236, which made us think that it wasn't a pagination type issue), and using NextToken in a repeat call to the same method gave us the few remaining results.
Thank you for your prompt response!

OAuth throws null reference exception

Lately the Nemiro.OAuth api is throwing null reference exceptions for some reason. After getting the lates versoin Nemiro.OAuth v1.12.0 and Nemiro.OAuth.loginForms v1.6.0 it started to behave like this, haven't changed my implemented logic in any way.
My file structure in dropbox:
https://www.dropbox.com/home/Apps/MyApplication/MyFolder/SubFolder/Some%20folder1/MyFiles
Old and new uri:
/MyFolder/SubFolder/Some folder1/MyFiles/somefile.png
When I call OAuthUtility.Post it shows following error message:
I'm using following logic to handle the request:
string oldUri = oldPath.ToUri();
string newUri = newPath.ToUri();
var paramCollection = new HttpParameterCollection
{
{"access_token", ACCESS_TOKEN},
{"from_path", oldUri },
{"to_path", newUri },
{"root","auto"}
};
OAuthUtility.Post
(
"https://api.dropboxapi.com/1/fileops/move",
paramCollection
);
I already checked that file exists in dropbox, my access token is valid, also, as you can see the path is correct.. Also it fails for other operations like
https://content.dropboxapi.com/1/files_put/auto{0}/{1}
What could cause this?
Could it be something with new Dropbox api V2?
Update
It actually works, but throws null reference exception at the same time..
That is pretty annoying, that means I need to wrap each operation in try catch block. Also, when I created new console application and executed the same code, it worked without any exceptions. Which means, something is wrong in my project.
0. Dropbox API v1 has been deprecated:
https://blogs.dropbox.com/developers/2016/06/api-v1-deprecated/
...In order to provide our developers with the most up-to-date features and support a single, consistent platform, we’ll be turning off API v1 a year from now, on 6/28/2017.
It remains approximately two months :-) I recommend switching to the new version of the API.
1. Do you pass the URI? But why are you doing this? Just use a string path relative to the root directory of the application. I tried to use a URI, this code does not work for me, the server returns an error 404.
I used relative paths and checked the code and do not see any problems.
If possible, show the full code in which the problem occurs.
Or you can send the project to me by email: aleksey.nemirogmail.com

XML-RPC .NET call with associative array

I'm trying to perform some actions on a remote server using the XML-RPC .NET library and C#. I have no prior experience using this protocol but most examples seemed pretty straight forward. But the server I'm trying to communicate with seems to parse commands slightly different than most examples I've seen.
All calls are made using a 'perform_actions' function and it expects a list of action(s) along side with it as parameter. Fortunately there's a pretty decent documentation with some code samples included but these examples are done in Ruby/Perl with which I have no experience. I've tried translating these to C# with which I believe I'm on the right path but I'm consistently getting the error"Server returned a fault exception: [400] Invalid request: expected list of actions."
My current code
[XmlRpcUrl("https://DOMAIN/admin/rpc")]
public interface iFace : IXmlRpcProxy
{
[XmlRpcMethod("perform_actions")]
XmlRpcStruct[] perform_actions(XmlRpcStruct struc);
}
public void GetData()
{
XmlRpcStruct actions = new XmlRpcStruct();
actions.Add("name", "registrations.accounts.list");
iFace proxy = XmlRpcProxyGen.Create<iFace>();
proxy.Credentials = new NetworkCredential("USERNAME", "PASSWORD");
XmlRpcStruct[] response = proxy.perform_actions(actions);
}
And here is a Ruby example from the API documentation which I was trying to replicate which is functional
require 'xmlrpc/client'
url = 'https://user:passwd#qmanage.example.com/admin/rpc'
c = XMLRPC::Client.new_from_uri(url)
# Call the action to list the access groups.
ags = c.call('perform_actions', [{
'name' => 'network.accessgroups.list',
'args' => {}
}])
The server doesn't really seem to recognize the XmlRpcStruct I'm sending as the error seems to complain about not receiving a list of actions. (I receive the same error if I send no parameter). However if I change the XmlRpcStruct to a regular string array it will complain about expecting a struct instead so the data isn't ignored entirely.
Is anyone able to help me in the right direction with my problem or does anyone know why this error is returned?
Finally managed to figure out my dilemma. Seems I had to pass an array of XmlRpcStruct's rather than just singular XmlRpcStruct, the following solved my problem:
XmlRpcStruct[] actions = new XmlRpcStruct[1];
XmlRpcStruct action = new XmlRpcStruct();
action.Add("name", "registrations.accounts.list");
actions[0] = action;
I just passed actions as parameter to the perform_actions function.

Creating Facebook Event in C# Returns #100 Invalid Parameter

I'm trying to put together a small app that will allow me to create events in Facebook. I've already got my Facebook app set up and have successfully tested a post to my feed through the application using the code below.
wc.UploadString("https://graph.facebook.com/me/feed", "access_token=" + AccessToken + "&message=" + Message);
When I try to take things to the next step, I've just hit a brick wall.
The code that I've written is here:
JavaScriptSerializer ser = new JavaScriptSerializer();
wc.UploadString("https://graph.facebook.com/me/events?" + "access_token=" + AccessToken, ser.Serialize(rawevent));
rawevent is a small object I wrote that puts together the elements of an event so I can pass it around my application.
I'm using a similar method using ser.Deserialize to parse the user data coming back from Facebook, so I believe this should work the other way too.
Setting the above code aside for a moment, I also have tried simply putting plain text in there in various formats and with differing levels of parameters, and nothing seems to work.
Is there something wrong with the way I'm approaching this? I've read over everything I could get my hands on, and very few of the samples out there that I could find deal with creating events, and when they do, they're not in C#.
I would appreciate any help on this. If you even just have a clean copy of JSON code that I can look at and see where mine should be tweaked I would appreciate it.
I have included a copy of what the ser.Serialize(rawevent) call produces below:
{"name":"Dev party!","start_time":"1308360696.86778","end_time":"1310952696.86778","location":"my house!"}
EDIT:
thanks to bronsoja below, I used the code below to successfully post an event to Facebook!
System.Collections.Specialized.NameValueCollection nvctest = new System.Collections.Specialized.NameValueCollection();
nvctest.Add("name", "test");
nvctest.Add("start_time", "1272718027");
nvctest.Add("end_time", "1272718027");
nvctest.Add("location", "myhouse");
wc.UploadValues("https://graph.facebook.com/me/events?" + "access_token=" + AccessToken, nvctest);
All the posting examples in the graph api examples in FB docs show using curl -F, which indicates values be POSTed as normal form data. Just key value pair like you did in your first example.
The error is likely due to sending JSON. If you are using WebClient you may be able to simply create a NameValueCollection with your data and use WebClient.UploadValues to send the request.
I've recently found that Facebook returns (#100) Invalid parameter when we are trying to post data when there is already a record on file with the same name. So for example, if you are creating a FriendList via the API, and the name is "foo", submitting another identical request for the same name will immediately return that error.
In testing events you probably deleted the "Dev party!" event after each test, or maybe changing the time since you don't want two events to collide. But I'm wondering if you duplicated your wc.UploadValues(...) statement just as a test if you would see that error again. You're either deleting your 'test' event or maybe changing names and didn't notice that two events with the same name might return the error.
What's really bad here is that the error comes back as a OAuthException, which seems very wrong. This isn't a matter of authentication or authorization, it's purely a data issue.
Facebook Engineers, if I'm right about how this works, it's a bug to return this error under these conditions, and this forum has many examples of related confusion. Please return more appropriate errors.

Categories

Resources