C# http request add json object in the content - c#

I'm making an http request post to an external api. I am constructing a json object to add to the request body. How can I check if the added body/content is correct before it is sent.
public async void TestAuthentication()
{
var client = new HttpClient();
var request = new HttpRequestMessage()
{
RequestUri = new Uri("http://test"),
Method = HttpMethod.Post
};
var jsonObj = new
{
data = "eneAZDnJP/5B6r/X6RyAlP3J",
};
request.Content = new StringContent(JsonConvert.SerializeObject(jsonObj), Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
}

If you are not sure whether the serialization works as intended, you could give it a shot in LINQpad or dotnetfiddle.net. See my example that returns the JSON on the console. These tools are great for quick prototyping a method or a snippet, if you are not sure if a piece of code works as intended.
You could also check in Wireshark, but that could be a bit of an overkill and works best if your connection if not encrypted (no HTTPS).
I personally tend to test code that calls some API the following way:
Make the called URL parameterizable (via the classes constructor)
If there is any variable data this data should be passed as the methods parameter(s)
For your test start an HTTP server from your test fixture (read on testing with xUnit or NUnit if you don't know what this means)
I use PeanutButter.SimpleHTTPServer for that
Pass the local IP to the class that accesses the API
Check whether the HTTP server received the expected data
Whether or not this kind of code shall be tested (this way) may be debatable, but I found this way to work kind of good. I used to abstract the HttpClient class away, but IMHO I would not recommend this anymore, because if the class accesses the API (and does not do anything else, which is important), the HTTP access is the crucial part that shall be tested and not mocked.

Related

How to clean string coming from API in C#

I am using C#
in my code, I call API
This API returns a string.
But the problem is when I read the API it comes with backslashes and quotations.
So if the returned value is Black\White's colors
It becomes "\"Black\\\\White's colors\""
or empty string is "\"\""
I wonder if there is a way to parse string the in a right way.
here is my code
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string str = client.GetStringAsync(url).Result;
Like this
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string str = await client.GetStringAsync(url);
//choose this if using NewtonsoftJson
string parsedWithNewtonsoft = JsonConvert.DeserializeObject<string>(str);
//choose this if using STJ
string parsedWithSystemTextJson = JsonSerializer.Deserialize<string>(str);
Choose one of the last two lines according to your preferred installed Json parser (manage nuget packages for the project and install either newtonsoft or system.text.json)
Don't use Result; use async proper (which means you have to make your method calls async all the way up the chain). If you strive to turn all your async calls synchronous then your app will spend a lot of tine sitting around doing nothing, waiting for network io to finish, when that time could be put to doing other useful work
Also, HttpClient is not supposed to be created anew every time you want to use it. Either configure your DI with services.AddHttpClient(); passing in options as necessary or if you aren't using DI/not writing a service of your own, you can get some ideas on how to use HttpClientFactory to manufacture HttpClients for you form this question - you may even be able to configure the default request headers as part of the manufacture so you don't need to set them in code
Finally, I should point out that I think there's a chance you're doing a lot more work than you need to if your API you're using publishes a swagger document; if it does you can use a tool like AutoRest (or the "add rest client" feature of visual studio, which uses AR), NSwag, WebApiClientGen etc and tell it "here is the api I want to use" and it'll make everything you need to call the api and return c# objects; you don't need to code any of this low level stuff, pushing data around and parsing responses, yourself

Is there a simple way to create a new outbound HttpWebRequest from the inbound request?

I need to effect a type of reverse proxy from C# code. (Yes, I know that IIS has a reverse proxy, but for several reasons, I need to do this from code.)
So, my controller action will "relay" the inbound request to another URL, then return the response. Kind of like this:
public string Proxy()
{
// This would be an extension method; it's currently hypothetical
var newRequest = Request.GetRequestToNewUrl("http://newurl.com");
// Make the request and send back whatever we get
var response = newRequest.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.Something))
{
return reader.ReadToEnd();
}
}
The proxied request (to newurl.com) should be identical to the inbound request (headers, body, cookies, etc.), just to a different URL.
I've been playing around with it, and it's more complex than I thought. The inbound Request is an HttpRequestBase, and the proxy request will be an HttpWebRequest. They are fundamentally different types, and there's no direct translation between the two. So far, it's been a tedious process of copy and translating properties.
Before I spend a ton of time debugging all this, is there an easier way? There are a fair number of different types to represent an HTTP request:
HttpRequestBase
HttpWebRequest
HttpRequest
HttpRequestWrapper
Is there a way I'm not aware of to simply "reuse" the inbound request, while changing the URL? Or should I continue with my translation from HttpRequestBase?
yes, it is possible. You can reuse the Request content from an incoming request and the forward it by creating a new request of your own. Create a new client with the address where the request was supposed to be forwarded. And do a get or post with new HTTP client and just return the result.
var client = new HttpClient
{
BaseAddress = new Uri(destinationBaseAddress)
};
return await client.PostAsync(requestUrl, Request.Content);

Pact.net: Get the request that was sent to the mock service

I'm writing the test inside the developers solution for one service and I'm mocking other third-party party services using pact mock service.
I need to verify the request that was sent to this mock service. So I need to get the payload that was actually sent. (The one that was actually stored into the log file starting with 'Received request ')
I'll greatly appreciate the help
Pact does the verification of the consumer request for you. Have a look at this example.
For the consumer, the test process is:
Describe the expected request
Describe the expected response
Call the code that the consumer uses to generate the response. (This step will actually hit the mock server- which returns the expected response if it gets the expected request).
Verify that the consumer code returned the expected data
Verify that the mock server received the correct request
I've bolded step 5, because that's the step that does the checking of the request.
(note also that if the request was not correct, step 3 doesn't generate the correct response, so step 4 will almost always fail)
Here's a breakdown of the example I linked above into the consumer test steps I've just listed:
Describe the expected request
_mockProviderService
.Given("There is a something with id 'tester'")
.UponReceiving("A GET request to retrieve the something")
.With(new ProviderServiceRequest
{
Method = HttpVerb.Get,
Path = "/somethings/tester",
Headers = new Dictionary<string, object>
{
{ "Accept", "application/json" }
}
})
Describe the expected response
.WillRespondWith(new ProviderServiceResponse
{
Status = 200,
Headers = new Dictionary<string, object>
{
{ "Content-Type", "application/json; charset=utf-8" }
},
Body = new //NOTE: Note the case sensitivity here, the body will be serialised as per the casing defined
{
id = "tester",
firstName = "Totally",
lastName = "Awesome"
}
}); //NOTE: WillRespondWith call must come last as it will register the interaction
Call the code that the consumer uses to generate the response
var consumer = new SomethingApiClient(_mockProviderServiceBaseUri);
//Act
var result = consumer.GetSomething("tester");
Verify that the consumer code returned the expected data
//Assert
Assert.Equal("tester", result.id);
Verify that the mock server received the correct request
_mockProviderService.VerifyInteractions(); //NOTE: Verifies that interactions registered on the mock provider are called once and only once
^ This is the step you need in order to verify that the request sent was correct.

How to determine if an HttpResponseMessage was fulfilled from cache using HttpClient

What is the equivalent to WebResponse.IsFromCache when using HttpClient and HttpResponseMessage?
Is there some HTTP header in the response that I can look at?
FYI: The Windows.Web.Http HttpClient (a similar API targetted at Windows 8.1 app development) does include an HttpResponseMessage.Source field that specifies where the result came from (common values are "cache" and "network").
The Windows.Web.Http classes are usable from C# and other .NET languages, from C++, and from JavaScript (when running as a WwaHost app like from the Windows app store).
Can I ask what you're trying to achieve? Are trying to avoid caching?
The reason for asking is I've looked at the source code for HttpClient (specifically HttpClientHandler) and the source for HttpWebResponse and I dont believe you can get this information from the headers.
HttpClient/HttpClientHandler does use HttpWebResponse internally however it does not expose all properties from HttpWebResponse :
private HttpResponseMessage CreateResponseMessage(HttpWebResponse webResponse, HttpRequestMessage request)
{
HttpResponseMessage httpResponseMessage = new HttpResponseMessage(webResponse.StatusCode);
httpResponseMessage.ReasonPhrase = webResponse.StatusDescription;
httpResponseMessage.Version = webResponse.ProtocolVersion;
httpResponseMessage.RequestMessage = request;
httpResponseMessage.Content = (HttpContent) new StreamContent((Stream) new HttpClientHandler.WebExceptionWrapperStream(webResponse.GetResponseStream()));
//this line doesnt exist, would be nice
httpResponseMessage.IsFromCache = webResponse.IsFromCache;// <-- MISSING!
...
}
So your options the way I see it are:
a) Look at the source code for HttpWebRequest to determine the logic for IsFromCache and retrofit this somehow into HttpClient (this may not even be possible, depends on what the logic actually does/needs)
b)ask the ASP.NET team for this property to be included with HttpResponseMessage. either directly as a property or perhaps they could 'keep' the HttpWebResponse
Neither of these options are that great sorry, hence my original question, what are you trying to acheive?
I've been struggling with this scenario recently as well.
What I needed was an integration test to verify that:
Responses for a newly created resource had the correct headers set by the server.
Subsequent requests for that resource were fulfilled from the client-cache.
Responses for an existing resource had the correct headers set by the server as well.
What I ended up doing was a twofold check:
A non-caching HttpClient to check the initial response:
new WebRequestHandler
{
AllowAutoRedirect = true,
UseCookies = true,
CookieContainer = new CookieContainer(),
CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.Refresh)
};
var client = new HttpClient(handler)
and a second HTTP client to check the client-side cache:
new WebRequestHandler
{
AllowAutoRedirect = true,
UseCookies = true,
CookieContainer = new CookieContainer(),
CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.Default)
};
var client = new HttpClient(handler)
To verify the source of response messages I compare the HttpResponseMessage.Headers.Date values from steps 1 and 2 (which will be the same if the response came from the client cache). For my third step I can just re-use the client from the first step and append an arbitrary string to the URL.
Disclaimer: this applies to .NET Framework 4.7 and ignores best practices concerning HttpClient usage but is seems to do the trick for me in my test suite. An explicit property like the one mentioned above would be preferable but does not seem to be available. Since the last reply here is already a few years old there might be better ways to handle this, but I couldn't think of one.

Utilizing Web API on client side

I have created a simple web api controller in mvc4 containing 4 methods (one for each CRUD operation). I'm able to use fiddler to test that the methods in my controller work.
I'm now trying to make a unit test to prove that these work. I've managed to serialize my client side object into json format, but now how do I use this string of json to actually invoke my methods?
If it helps, I am using Json.NET to serialize my client object - although I don't think this extention actually handles the delivery and retreival of it to the server.
Your unit tests should be written against the controller - so you don't need to make an actual HTTP request to unit test your Web API code, you just call the methods.
From a design perspective, if you want a restful Web API, the client should be able to send a standard HTTP message without having to serialize the request.
This is the kind of approach I have used to post an object to a restful Web API:
HttpResponseMessage response;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://url_to_service");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var responseTask = client.PostAsJsonAsync("api/resource/somethingelse", someObjectToPost).Result;
responseTask.Wait();
response = responseTask.Result;
if (response.IsSuccessStatusCode)
{
var contentTask = response.Content.ReadAsAsync<SomeResponseType>();
contentTask.Wait();
SomeResponseType responseContent = contentTask.Result;
}
else
{
//Handle error.
}
In this case, someObjectToPost is your client-side object, though you can leave it to Web API to serialize it for you. In the above example I am assuming the reponse is of fictional type SomeResponseType - you can also use ReadAsStringAsync if the response is expected to be plain text.
The code presented here by nick_w is correct. You need to use HttpClient object. And as Steve Fenton mentioned, to create unit test you don't want to do it - rather test directly against controller. But for the functional test you can do it. I've done same thing. I've created helper class so I need only to call one of Http helper methods, depending if it is GET or POST, etc. that I do. This helper uses generic types so it operates with any types that being passed.

Categories