I have a RestClient of type IRestClient that does a request and gets a response.
the response is of type IRestResponse.
In the Unit test using Nunit I do:
var response = new RestResponse<MyResponse>
{
Content = "some string"
};
this.mockRestClient.Setup(c => c.ExecuteTaskAsync(It.IsAny<RestRequest>()))
.ReturnsAsync(response);
In the code this happens:
var response =
(await this.client
.ExecuteTaskAsync(request))
.EnsureStatusCode(HttpStatusCode.OK, HttpStatusCode.BadRequest);
return response.ParseContent<MyResponse>().Data;
ParseContent method does this:
public static IRestResponse<T> ParseContent<T>(this IRestResponse response)
{
if (!(response is RestResponse fullResponse))
{
throw new NotSupportedException($"Currently requires a concrete {typeof(RestResponse).Name}");
}
}
The API works correctly in various environments but the Nunit integration test fails with the error
Currently requires a concrete RestResponse
When I debug it, it is of type RestResponse`1
As you can appreciate this is very hard problem to search both in Google but also here in Stackoverflow because no search engine considers the backtick.
Does anyone know what this is and how to make Nunit behave correctly?
Type checking becomes a nightmare if instances are of T`1 type instead of T
Why does Nunit test project generate a new type while the actual application doesn't?
RestResponse<MyResponse> does implement IRestResponse, but it does not extend RestResponse.
In C#, generic types and their non-generic equivalents are not actually the same class. A response that doesn't have a specific type of data with it is represented in this framework as a RestResponse, whereas responses with a data type are represented as RestResponse<T> (which is represented by a back-tick when ToString()'d.
I'm not entirely clear on the intent of your ParseContent<> method, or how the code works outside of unit tests, but you may want to try creating your test data like this:
var response = new RestResponse
{
Content = "some string"
};
That way, you're providing the "concrete RestResponse" type that the method is asking for. And I assume the method itself produces a RestResponse<MyResponse> based on the contents of the RestResponse you pass in.
Related
I currently have an endpoint in my project:
[HttpPost("process")]
public IActionResult Process (string Val1, [FromBody] object Json)
{
//processing.....
Return Ok(...);
}
And on my client side I am trying to call this endpoint with WebClient like so:
string response = null;
string body = "{}";
using (var client = new WebClient())
{
client.UserDefaultCredentials = true;
client.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
response = client.UploadString("localhost:55555/api/process?Val1=Param", body);
}
Here's where my concerns are:
For this endpoint, I will typically be passing a JSON object
However, I want this endpoint to also NOT require a body, I would want it to be empty, as the endpoint should not require it
If you look at my body variable - I am setting it to "{}" otherwise I've not found a different way to pass "EMPTY" body to the endpoint
Questions:
How do I properly pass an EMPTY body to this endpoint? (this endpoint will be used by different clients, and I am just looking for best practice approach to this?
In my endpoint, I have [FromBody] object Json parameter. Is it a better practice to have it be as object or can I alternatively do JObject that could still accept an Empty body
Forgive my "noobness" with these questions if they seem obvious, I'm just getting started in the API development and want to make sure I am using best practices.
You're currently using a WebClient, which is outdated in favour of HttpClient (see this answer). When using HttpClient you can post empty bodies as follows: await client.PostAsync("localhost:55555/api/process?Val1=Param", null);
As for your second question. Look into Data Transfer Objects, aka DTOs. They are in a nutshell dumb types you can use purely for passing and receiving data through your API, you can add things like validation to them as well. Using object or JObject is only needed if you're receiving dynamic data, otherwise use DTOs where possible.
I'm working on a WEB API application made with .NET Framework. Right now i'm working alonside a supplier to help and integrate their WEB API with our system. One of their latest change broke my code. Since i'm using RestSharp library i'm expecting the response to always correspond to a specific type of object, independently if with was a success or failure from their side.
IRestResponse<T> response = await restClient.ExecuteAsync<T>(request);
If the response is successful they will send a json response like this
{message:"", jobNr:"2312312", status:"1"}
And then they changed the code, so that if any request input was wrong they will send a list of errors, so the response will be like this:
[{code:100, message:"contact phone is wrong"},{code:101, message:"the email is not provided"}]
I don't like this approach, since i think they should give a response for errors like this:
{errorMessages:[{code:100, message:"contact phone is wrong"},{code:101, message:"the email is not provided"}]}
But since it is not in my hands. How should i deal with it? Just parse the json response and assing to different types of objects? Thanks.
Yes, the response should be parsed manually.
Assuming RestSharp is still in charge and the original API returns errors entitled with BadRequest status code, below extension tries to deserialize the content as an array of errors (a type consists of a code and a message just like mentioned in question).
public static Error[] AsErrors(this IRestResponse response)
{
var empty = new Error[] { };
try
{
return response.StatusCode == System.Net.HttpStatusCode.BadRequest
? JsonSerializer.Deserialize<Error[]>(response.Content)
: empty;
}
catch (JsonException)
{
return empty;
}
}
Considering the NormalContent is what you truly expect as response, the usage will be:
// after creating client and request ...
var response = client.Execute<NormalContent>(request);
var errors = response.AsErrors();
if (errors.Any())
{
//Deal with errors
}
else
{
//response.Data gets populated with RealResult
}
NOTE: Using the procedure as an extension depends on how common is the response pattern in your case.
I've looked at several related examples on SO and tried a number of methods to get this to work, but I become more confused with each attempt.
I'm trying to search through the Wordpress.org plugin repository API and get a list of plugins from the search results.
The endpoint is: http://api.wordpress.org/plugins/info/1.0/
The two important bits of data to pass are "action" and "search." The action I'm interested in at the moment is "query_plugins", and passing a search string along in the request.
This is a PHP equivalent:
$payload = array(
'action' => 'query_plugins',
'request' => serialize(
(object)array(
'search ' => 'search-phrase',
)
)
);
$body = wp_remote_post( 'http://api.wordpress.org/plugins/info/1.0/', array( 'body' => $payload) );
The only real documentation I've been able to find is from this blog post (which is where I got the above sample code): https://dd32.id.au/projects/wordpressorg-plugin-information-api-docs/
I'm using RestSharp to build the request, with code along these lines:
var client = new RestClient("http://api.wordpress.org/");
var request = new RestRequest("plugins/info/1.0", Method.POST);
request.AddParameter("XXX", "XXX");
var response = client.Execute(request);
var content = response.Content;
the "request.AddParameter("XXX", "XXX"); above is where I'm stuck. I need to build the PHP array equivalent in C# (and serialize it properly?) so that the API will accept the request. I've tried several variants and combinations, from everything as primitive as:
request.AddParameter("action", "query_plugins");
request.AddParameter("search", "keyword");
// and variants such as request.AddParameter("request", "[{ search: keyword }]);
Which I knew wouldn't work (but took a stab with anyway), to using a Dictionary() with the action and search parameters, and attempting to serialize it in several ways (most recent involved JsonConvert.SerializeObject).
At this point I don't know which tree I should be barking up, I have a feeling I'm not even in the right vicinity. I'm not even sure if I should be serializing to JSON, XML, or just a byte-stream (as I understand that's what the PHP serialize() method does, if I'm not mistaken), and I'm not sure the best approach to package all of the data I need to send off in the request.
This seems to work. Instead of POST, use GET
See the working sample here..
https://dotnetfiddle.net/rvL9eC
var client = new RestClient("http://api.wordpress.org/");
var request = new RestRequest("plugins/info/1.0", Method.GET);
request.AddParameter("action", "query_plugins");
request.AddParameter("search", "oauth");
var response = client.Execute(request);
var content = response.Content;
I am using System.Net.Http's HttpClient to call a REST API with "POST"
using the following code:
using (HttpRequestMessage requestMessage = new HttpRequestMessage(
HttpMethod.Post, new Uri(request)) { })
{
response = await httpClient.PostAsync(request, objectContent);
}
The "objectContent" is currently this -
objectContent = new ObjectContent(jsonContent.GetType(),
jsonContent,
new JsonMediaTypeFormatter());
I was wondering what difference it makes if this was a StringContent rather than an ObjectContent like this?
objectContent = new StringContent(content);
objectContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
Both work fine. Because it is JSON, i tend to assume that StringContent would make sense. But when is ObjectContent to be used because pretty much all content sent is a "string".
I was wondering what difference it makes if this was a StringContent
rather than an ObjectContent like this?
In your example there won't be any difference. ObjectContent simply allows a "wider" range of types to be sent via HttpClient, while StringContent is narrower for string values only, such as JSON.
StringContent is a slim wrapper around ByteArrayContent, and actually stores the value passed as a byte[]. You simply get the benefit of not needing to transform your string back and forth.
Edit:
Given the fact that you're posting a JSON, you can even make it less verbose by using HttpClientExtensions.PostAsJsonAsync<T>:
await httpClient.PostAsJsonAsync(url, json);
If someone will search how to send request by PostAsync in .NET Core 2.1:
I did not found PostAsJsonAsync method in HttpClient, but your solution with setting:
objectContent = new StringContent(content);
objectContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
"do the job" perfectly also in .NET Core.
Edit:
Additionally If you want add your own header you can type:
objectContent.Headers.Add("Your header", "Value");
ObjectContent is used to format more complex Mime types using built-in or custom-written formatters. It is OK to use ObjectContent for a simple string as well, it doesn't make much difference except for the performance which (IMHO and not checked) may be better with StringContent, since it may have been optimized specifically for strings
I can see the object in Fiddler but the object is not deserializing on my end. Has anyone seen this before?
"Response is null" or "Response contains nulls" or "Request is null" or "Request contains null" almost always mean that you have a namespace mismatch. For instance, the response may contain:
<response xmlns="http://foo.com"/>
but should in fact be
<response xmlns="http://bar.com"/>
In this case, null will be received.
I had the same problem, and as suggested the namespace problem was the root cause.However, my proxy class has nested classes and long chain of nested namespace.
It was confusing to identify the correct namespace to apply in Cs code for proxy class. Here, i describe how to figure out the namespace which is required to be updated in client proxy.
What i did was intercept the request in ClientMessageInspector class, AfterReceiveReply method (Enables inspection or modification of a message after a reply message is received but prior to passing it back to the client application.) Verified the namespace of the object which were returning null in Response by using XMLDocument. I updated the proxy class with the namespace retreived from XML. After making the changes, the objects were not null in response.
public class MyMessageInspector : IClientMessageInspector
{
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message request, object correlationState)
{
MemoryStream ms = new MemoryStream();
XmlWriter writer = XmlWriter.Create(ms);
request.WriteMessage(writer);
writer.Flush();
ms.Position = 0;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ms);
this.ReadMessage(xmlDoc);
ms = new MemoryStream();
xmlDoc.Save(ms);
ms.Position = 0;
XmlReader reader = XmlReader.Create(ms);
Message newMessage = Message.CreateMessage(reader, int.MaxValue, request.Version);
newMessage.Properties.CopyProperties(request.Properties);
request = newMessage;
}
private void ReadMessage(XmlDocument xmlDoc)
{
XmlNode v1 = xmlDoc.GetElementsByTagName("XPAth");
//Actual Namespace in XML, which should be used in Proxy Class
string namespaceURIForObjectInXML = v1.NamespaceURI;
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
}
}
I had a similar case where I created a client via SVCUTIL / Service Reference from VS. The response was received successfully with correct data (confirmed via IClientMessageInspector.AfterReceiveReply method) however the values at the object level were not being populated. There were no de-serialization errors (confirmed via system.diagnostics output)
The problem was twofold:
1) Certain objects were named exactly as their types but had different namespaces from their types. This seems to have confused the proxy generator in assigning the namespace parameter (in the System.Xml.Serialization.XmlElementAttribute annotation) of the class to the one of the object
2) The order parameter (in the System.Xml.Serialization.XmlElementAttribute annotation) of the properties was not required and also the namespace parameter was missing
so from: [System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=0)]
to: [System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Namespace="http://www.whathevernamespaceiscorrect.com")]
So basically, in the generated proxy I needed to fix the namespace of the class to the one specified in the type, and replace the order parameter with the namespace parameter setting it to the correct namespace according to the wsdl
The only reason I can think of is a contract mismatch. Although it's strange if no validation error is thrown. Are you using a client generated from the correct WSDL? Is it a WCF client or a SOAP one? The former one does validation, I'm sure, but schema mismatches may slip through the latter.
Every time this happens to me, it's because I need to update my service references. Try that and let me know what happens :)
Solved it... or at least have workaround. In the Java code the #XmlElementRefs and #XmlElementRef should have been #XmlElements and #XmlElement respectively (as well as the "type" attribute it needed a "name" attribute).
Guessing if I'd posted this as a new question with a Java tag as well as C# and web-services some hawk-eyed stackoverflower would have spotted this schoolboy error.
I had a similar issue which i resolved by checking the Order value in the Reference.cs.
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
The order of the return parameters had changed but updating my service reference in visual studio didn't change the "Order" value.
Check that parameters returned in Fiddler/SoapUI are the same as in your proxy generated class.
Ensure the definition / specification matches the output. Compare the WSDL (in browser) and the response (in SOAP-UI, Fiddler), e.g.
WSDL uses camel case (lastName) and
response uses underscores (last_name).