Is it possible to set a custom request method with RestSharp? - c#

I'm working on a C# console application which calls external REST APIs with RestSharp.
The issue now is that I have to access an API that only allows a custom request method like FOOBAR instead of the traditional GET or POST.
using RestSharp;
var request = new RestRequest();
request.Method = Method.POST;
Unfortunately, I haven't seen anything pertaining to custom request methods in RestSharp's docs or GitHub issues section.
Keep in mind that I only have a basic knowledge on this, so my trials might be considered silly.
I've tried assigning a string to it but it only accepts an enum.
request.Method = "FOOBAR"; // Does not accept strings
I've also tried converting a string to enum using code from this answer, but this defaults to a GET. It might be like that due to my converted string not being in their enum Method.
Enum.TryParse("FOOBAR", out Method customRequestMethod);
request.Method = customRequestMethod; // Defaults to GET
If this is not possible with RestSharp, is this feature doable with HttpClient or Flurl?

Related

Restsharp parameter behavior when setting ParameterType=GetOrPost

I face a weird intermittent issue with RestSharp. I use it to submit a POST authentication request to a server. But under certain conditions that I cannot isolate yet, this authentication call fails. By looking at the server log, I see a GET request instead of a POST. And I really wonder how the hell it is possible.
Here is the code to submit the authentication request :
var client = new RestClient(m_baseUrl);
var request = new RestRequest("https://dummyserver.com/api/auth", Method.POST);
request.AddParameter("client_id", apiCredentials.ApiKey, ParameterType.GetOrPost);
request.AddParameter("client_secret", apiCredentials.ApiSecret, ParameterType.GetOrPost);
request.AddHeader("Content-Type", "multipart/form-data");
IRestResponse response = await client.ExecutePostTaskAsync(request);
Since it is a distributed application, I don't have much info on the client request. Telemetry just confirms that the authentication failed.
Is it possible (known bug) that RestSharp transformed this request into a GET?
And, second question, is there any difference on the request being created with those two syntaxes:
request.AddParameter("client_id", apiCredentials.ApiKey, ParameterType.GetOrPost);
request.AddParameter("client_id", apiCredentials.ApiKey);
I need parameters to be submitted as form-data for security purposes.
Thanks for your help.
I don't think it's possible that a POST request gets executed as GET. Consider that you have some code (not the code from your question), which does that. Even using ExecutePost is redundant when you explicitly set the request type in the RestRequest constructor.
Concerning the second question, there's no real difference. The default parameter type is GetOrPost. I also believe that we use multipart/form-data for POST requests by default where there's no JSON or XML body.
You can easily find it by looking at the code of RestSharp.
Although weird, I've experienced a similar issue with you.
My solution is to use ExecuteAsPost():
var response = client.ExecuteAsPost(request, "POST");

Http Put and querystring

I have two problems. I am trying to interact with a Web API that is wanting a HTTP PUT. I am trying to pass the parameters as part of the querystring. Unfortunately, I am not really sure how to do that. Do I include them in with the first parameter of the PutAsync method as shown below?
The other question I have is I am unsure what needs to be coded for the HTTPContent object when using the PutAsync method. I am trying to pass the parameters in the querystring instead of other methods that might be used. Most of the examples that I can find are passing the data as json.
using (var apiManagementSystem = new HttpClient())
{
apiManagementSystem.BaseAddress = new Uri("https://thedomain.com/api/");
apiManagementSystem.DefaultRequestHeaders.Clear();
apiManagementSystem.DefaultRequestHeaders.Add("SessionID", _sessionID);
HttpContent httpContent = new /* What do I do Here? */
responseMessage = apiManagementSystem.PutAsync("Product/someID?available=N", httpContent).Result;
}
My finished url should be something like this.
https://thedomain.com/api/Product/someID?available=N
This API that I am communicating with is a Rest API

MailChimp integration with asp.net

I am facing a issue with mailChimp, I make a PUT call with HttpWebRequest for unsubscribing a user from the list, it works fine but the same thing I had done with POST call with status as unsubscribed then it also works. So which call should I make for unsubscription?
Example code with mailChimp Api key in added in HttpWebRequest headers:
string subscriberEmail = "XXXXXX";
//Create JSON Object for sending to MailChimp
var subscribeRequest = new
{
status = "unsubscribed",
email_address = subscriberEmail, //E-Mail
};
var requestJson = serializer.Serialize(subscribeRequest);
HttpWebRequest httpWebRequest =(HttpWebRequest)HttpWebRequest.Create(https://XXX.api.mailchimp.com/3.0/lists/XXXXXX/members");
httpWebRequest.Method = "POST";
httpWebRequest.ContentType = "text/json";
httpWebRequest.Accept = "text/json";
Rather than a hard-rule on what to choose, here is an explanation on why both Verbs work.
A lot of API providers support the same operations for both the PUT and POST verb.
In pure REST terms, these verbs have specific guidelines of POST for creating new resources and PUT for updating resources.
But in most real-world APIs, the lines blur between following 100% REST guidelines vs. providing action oriented APIs. e.g. (Unsubscribe, Cancel etc.)
In that, it really doesn't matter if you use POST or PUT and hence a lot of API providers provide support for both. Internally they tend to always go through the same code path, and hence you should see the same behavior in both cases.
When both PUT and POST are available for action oriented APIs (unsubscribe, cancel etc.) I have seen folks preferring the POST Verb, since it is more intuitive and natural on a non-read-only API.
But there is really no hard rule, so whatever you decide stick to it.

Why does my API return {}

I've created a .NET API, but when I try to use it I'm getting strange results.
If I go to the URL of an API call in Chrome I get the result I would expect, in XML format, but if I try it in IE it downloads a file and when I open it it just says {} or sometimes [{},{},{},{}] if I try a call that returns an array.
I've also tried using a webclient.
WebClient web = new WebClient();
var data = web.DownloadString("http://myAPI.example.com/api/MyAPI/APIMethod?parameter1=hiImAParameter");
This also returns empty {}.
I've tried searching online, but I don't see any mentions of this problem anywhere. I'm sure I must be missing something somewhere, but I've tried looking over how I set up my API, and it all looks fine to me.
Edit:
Here's the response I get in Chrome.
<ArrayOfRoute xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/TimePointModel">
<Route>
<RouteId>11235</RouteId>
<RouteName>Fibonacci</RouteName>
<Status i:nil="true"/>
<Width>0</Width>
</Route>
</ArrayOfRoute>
It returns XML on Chrome because of Chrome's accept headers. It's supposed to return JSON on IE, but for some reason the JSON is empty.
This is in my api controller:
[AcceptVerbs("GET")]
public IEnumerable<Route> APIMethod(double parameter)
{
return new Manager(parameter).GetRoutes();
}
This is in my Global.asax.cs:
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHttpRoute(
name: "APIMethod",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "APIMethod", id = System.Web.Http.RouteParameter.Optional }
);
}
Edit:
This works great when I do an API call which doesn't require parameters.
WebClient web = new WebClient();
var data = web.DownloadString("http://myAPI.example.com/api/MyAPI/SimpleAPIMethod");
I've been doing research, and I tried adding parameters like this:
NameValueCollection myQueryStringCollection = new NameValueCollection();
string myParameter = "hiImAParameter";
myQueryStringCollection.Add("parameter1", myParameter);
web.QueryString = myQueryStringCollection;
var data = web.DownloadString("http://myAPI.example.com/api/MyAPI/APIMethod");
I've noticed that the number of empty {} in my array matches the number of items in the array if I put the full url with the querystring into chrome. It just empties them out for my webclient.
I also tried adding
web.Headers[HttpRequestHeader.ContentType] = "application/json";
before making the call, but there's still no change in the result.
And I tried to follow that tutorial, but it's written for a console application and they're using HttpClient. I can't do that because I can't do Asynchronous calls. This is to be used by a website. That's why I'm using WebClient. I also tried using StreamReader with HttpWebRequest and HttpWebResponse, but it had the same problem as I've been encountered with WebClient.
Without more information, it's a bit hard to diagnose your issue. However, I would say that it is likely your web API is interpreting the expected response type and providing an empty result as it does not support responses of that type, such as happens with ASP .NET Web API websites.
In that sense, the DownloadString is indicating it is expecting a text/html response. You should probably download the Microsoft ASP .NET Web API Client Libraries with NuGet. This library will give you HttpClient which has support for making the queries you want to make with responses such as application/json and application/xml.
You can view a tutorial on how to do the calls right here.
If you want it to work from your web browser, you need to ensure the Accept header field is correct, as you mentioned. Ensure it is being communicated with IE by using something like Fiddler.
I figured out what the problem was. I needed to add [DataMember] attributes to the attributes of the items in the list. I didn't realize it was left out of the return type of that call.

How to create an otrs ticket using a soap request

The lack of documentation on this subject coupled with the fact that I'm struggling with a learning curve on all fronts and making me really confused about where to start. I need to get this done using C# if possible. I apologize for the vagueness of this question, but I'm really lost. I would love links to comprehensive guides/references.
In my efforts to get this done, I've run into the following problems/questions:
I've created a web service using the otrs gui, with the operation CreateTicket, but requests via C# to my chosen namespace are returning 404 (not found). When I try to add a service reference or web reference with that namespace, I get the same error. However, when I plug that namespace into my browser as the url, it displays "customer.pl".
Can I send a soap request without adding the web service as a service reference in visual studio? Given the previous problem I'm having I can't do it that way. Would I just build the soap request string and write it to the web request's data stream with http://domain/rpc.pl as the uri?
If the answer to the previous question is yes... When trying the below code segment I get an internal server error (500) on the last line. However the header looks like a SOAP header which confuses me because I wouldn't have thought it got that far.
var document = new StringBuilder();
document.Append("<UserLogin>some user login</UserLogin>");
document.Append("<Password>some password</Password> ");
document.Append("<Ticket>");
document.Append("<Title>some title</Title> ");
document.Append("<CustomerUser>some customer user login</CustomerUser>");
document.Append("<Queue>some queue</Queue>");
document.Append("<State>some state</State>");
document.Append("<Priority>some priority</Priority>");
document.Append("</Ticket>");
document.Append("<Article>");
document.Append("<Subject>some subject</Subject>");
document.Append("<Body>some body</Body>");
document.Append("<ContentType>text/plain; charset=utf8</ContentType>");
document.Append("</Article>");
//var uri = new Uri("http://domain/injest");
var uri = new Uri("http://domain/rpc.pl");
var httpWebReq = (HttpWebRequest)WebRequest.Create(uri);
var bytePostData = Encoding.UTF8.GetBytes(document.ToString());
httpWebReq.Timeout = 5 * 1000;
httpWebReq.Method = "POST";
httpWebReq.ContentLength = bytePostData.Length;
httpWebReq.ContentType = "text/xml;charset=utf-8";
//httpWebReq.TransferEncoding=
//httpWebReq.ContentType = "application/xml";
//httpWebReq.Accept = "application/xml";
var dataStream = httpWebReq.GetRequestStream();
dataStream.Write(bytePostData, 0, bytePostData.Length);
dataStream.Close();
var httpWebResponse = (HttpWebResponse)httpWebReq.GetResponse();
Even if all you can offer is where to start, it would help me to know how to proceed, as I'm stumped.
You're using the rpc.pl endpoint which is part of the 'old' RPC-style interface.
You mention you added the web service via the GUI which means you're using the 'new' Generic Interface, which is indeed much easier from .Net.
The address of the endpoint is /otrs/nph-genericinterface.pl/Webservice/GenericTicketConnector or whatever you have called the web service in the admin section.

Categories