HttpWebRequest and Response - c#

I am writing a c# program for HttpRequest and Response as below.
public string Methods(int id)
{
HttpWebRequest Request = (HttpWebRequest) WebRequest.Create(#"http://172.17.18.16:8082/item/detail/90");
Request.Method = "Get";
WebResponse Response = Request.GetResponse();
IHttpRequest request = (IHttpRequest)Request;
IHttpResponse response = (IHttpResponse)Response;
SetupRequest(request, response, session);
//Request.Method = Method.Get;
string m = request.Method;
TemplateManager mg=new TemplateManager();
ItemController it = new ItemController(mg);
it.Detail();
return m;
}
Here IHttpRequest and IHttpResponse are the Interfaces which are already created.
I want to assign HttpWebRequest Request to the interface so that the remaining functionality should happen itself. I am getting error in casting lines as
Unable to cast object of type 'System.Net.HttpWebRequest' to type 'HttpServer.IHttpRequest'.
Please help me to find a solution
Thanks

These lines are never going to work:
IHttpRequest request = (IHttpRequest)Request;
IHttpResponse response = (IHttpResponse)Response;
because neither of them implement the interfaces IHttpRequest or IHttpResponse. To make an inbuilt class implement your own interfaces you will have to extend it (derive a new class from it), I'm not sure exactly why you are trying to do this with these two classes, but typically you would only pass them around as an interface if you wanted to change how they are implemented; i.e. if you wanted to write a replacement for HttpWebRequest, or if you were using a dependency injection container (and even this doesn't require interfaces to work).
Check here for their doco online: HttpWebRequest & HttpWebResponse

Related

Cover with unit test WebRequest c#

public void HandleRequest(WebhookModel model)
{
var strRequest = "cmd=_notify-validate&" + ipnContext.RequestBody;
var webRequest = FormRequest(strRequest);
var requestStream = _webRequestWrapper.GetRequestStream();
var responseStream = _webRequestWrapper.GetResponse().GetResponseStream();
using (StreamReader reader = new StreamReader(responseStream))
{
model.Verification = reader.ReadToEnd();
}
}
private WebRequest FormRequest(string strRequest)
{
var webRequest = WebRequest.Create("some url is over here");
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = strRequest.Length;
return webRequest;
}
Where _webrequestWrapper just a wrapper around WebRequest class.
So, my question is how I can mock _webRequestWrapper.GetResponse().GetResponseStream() ? The problem is that there is no problems with mocking GetResponse() because of we create for it wrapper around WebRequest, but the problem is with GetReponseStream, because it returns a Stream object, how I can test HandleRequest() method?
I really have not any ideas about it. Please help me.
Thanks
I don't see anything worth testing in HandleRequest(WebhookModel model).
The only thing your code is doing is model.Verification = reader.ReadToEnd();, so you'd be testing whether you can set a property on an object. I'm pretty sure that's going to work in most cases.
Any issues that you encounter with WebRequest and related I/O classes should probably be handled using try/catch blocks.
Unit tests are good for business logic or general assumptions about inputs and outputs, and should be fairly easy to create and maintain. If you find yourself spending lots of time mocking I/O classes, then consider whether you can break out testable units of work into separate (preferably static) methods. You'll make your life and coworkers' lives easier.

Call WebApi from another WebAPI in same application

I have several webAPIs developed in MVC WebAPI such as
public IHttpActionResult SendBroadcast(FinalPayload FinalPayload)
And I want to call another web api from inside this API. All my APIs are in the same application. The signature of the second API is
public IHttpActionResult SendMessage(Notifications)
From the first API i tried
this.SendMessage(Notifications)
and got error message something like reference to static object ....
I wanted to know if this way of calling webAPI is allowed or do I have to invoke a web client or similar such.
Any help in this will be much appreciated.
1st approach
You have to redesign the code in your application i.e. Solution.
Create a class library project. Create an interface for the logic/functions which are common and consumed by different projects.
Implement the interface in the class library project.
In different projects(i.e. WebAPI projects) use the interface to access the common functionality.
2nd Approach
As thought by you, of-course you can create a web client to access the Web API in another project.
Its not a good design and your problem is not ACTUALLY solved (just circumvented).
Poor efficiency, as webclient will use http request to access the code in same solution.
For future maintenance you may end up creating multiple web clients.
No, as usual you'll need to create a new web client in order to consume the API.
What #Marcus H has suggested in the comment is doable too, just wrap the logic inside second API into a separate method (be it instance or static) and invoke it from your first API will do the trick.
Yes you can. You can create a webClient in your controller method method2 that calls method1.
This is a little helper class you could use to help you:
namespace Api.Helpers
{
public static class ApiHelpers
{
private static string HttpGet(string url)
{
WebRequest request = WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials;
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
response.Close();
return responseFromServer;
}
public static string HttpPostJson(string url, string json)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
};
}
}
}
If you want Cookie based authentication, then just use RestSharp instead.
If you use Postman the Chrome extension tool, then if you can access your endpoint, you can automatically generate your C# code.
Simply put the webclient code within the Controller method, and one API call will effectively chain to another.
so in your ApiController you'd write something like:
IHttpActionResult method1() {
var result = ApiHelpers.HttpGet("http://thing.com/test");
return Ok(result);
}

C# Asana POST new task returns error 400 (Bad request)

I have a problem with creating new task in Asana from my app.
Post method:
protected static T Post<T>(string route, object action = null, object parameters = null) where T : BaseResult, new()
{
var result = new T();
try
{
var actionUrl = GetActionUrl(route, action);
var request = (HttpWebRequest)WebRequest.Create(actionUrl);
request.Credentials = CredentialCache.DefaultCredentials;
request.Accept = "application/json";
request.Method = WebRequestMethods.Http.Post;
request.Proxy.Credentials = CredentialCache.DefaultCredentials;
request.Headers.Add("Authorization: Bearer " + ApiKey);
if (parameters != null)
{
var contentJSON = JsonConvert.SerializeObject(parameters);
request.ContentType = "application/json";
using (var s = request.GetRequestStream())
using (var sw = new StreamWriter(s, Encoding.UTF8))
sw.Write(contentJSON);
}
var response = (HttpWebResponse) request.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream()))
{
var data = reader.ReadToEnd();
result = JsonConvert.DeserializeObject<T>(data);
}
}
catch (Exception ex)
{
result.IsOk = false;
result.Message = ex.GetMessage();
}
return result;
}
Action URL: https://app.asana.com/api/1.0/workspaces/MyWorkspace/tasks
JSON:{"data":{"name":"TestTask1","notes":"Test note","workspace":"*MyWorkspace*","assignee":"*MyAssignee"}}
But Asana returns me "The remote server returned an error: (400) Bad Request."
If I change request.ContentType to "application/x-www-form-urlencoded", I get no errors, but Asana returns me new task with empty fields.
What my next steps to fix issue should be?
Thank you
If you're using an ApiKey (and not a Personal Access Token), I believe that your Authorization Header should be
"Authorization: Basic " + EncodedAuthInfo
where
EncodedAuthInfo = Convert.ToBase64String(Encoding.Default.GetBytes(ApiKey + ":"))
See How do I connect to the Asana Rest API using c#? or the Using Basic Authentication section in https://asana.com/developers/documentation/getting-started/auth for details on using basic authentication.
I'm also a little confused by what you mean when you say that
JSON = {"data": {"name": "TestTask1"} ...
Is this the HTTP response that you expect?
Anyways, hopefully what I've outlined helps.
Hmm. I think I've got what's blocking you sorted out.
Imagine the scenario where you post to
https://app.asana.com/api/1.0/workspaces/123456/tasks
and you pass in the request body the parameter
"workspace":"789012"
What should the Asana platform do with this data? You've inadvertently specified the workspace twice with conflicting numbers. For this reason, you cannot specify the workspace id in the data when hitting an endpoint which also contains the workspace id in the URL.
The documentation is confusing on this point, because we don't clarify which parameters are found in the URL and which parameters are found in the JSON in the request body. I'm actually fixing this very soon! If this is indeed what's causing the issue, I'm sorry that we were not clear on this.
Personally, I think it might be a better user experience to allow the workspace to be duplicated in the parameter data if and only if it's identical to the one in the URL, but right now, we simply check to see that there is only one value for the workspace id. If there are more than one, even if they are the same one, we return the 400 error code.
You might consider parsing the response body, even on errors. In it, we try to provide fairly decent information about what was wrong about the request. For example, when testing my hunch about your request, what I got back was:
"errors":[{"message":"Duplicate field: workspace", ...}]
If we've done a good job about sending back informative messages, I hope you'll find this even more useful than an Asana sandbox! If this is not the issue, feel free to comment; I'll be happy to dive into this further.

Is there a way to replace the JSON formatter in ASP.Net WebApi only for the return?

We have found that using an attribute on the controller we can have the controllers default json formatter replaced :-
public class WcsControllerConfigAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
var mediaType = ConfigurationManager.AppSettings["WcsMediaType"];
if (mediaType == "application/json")
{
var formatter = controllerSettings.Formatters.OfType<JsonMediaTypeFormatter>().Single();
controllerSettings.Formatters.Remove(formatter);
formatter = new JsonMediaTypeFormatter
{
SerializerSettings =
{
ContractResolver = new NullableValueContractResolver(),
NullValueHandling = NullValueHandling.Include,
DefaultValueHandling = DefaultValueHandling.Populate
}
};
controllerSettings.Formatters.Add(formatter);
}
}
}
But this seems to have the effect of replacing the formatter not only for the result we wish to return but also for the json body of the incoming request. Is there a way to replace only the formatter for the response and not the request?
Edit: OK In response the doctors remark I think I should possibly state what my ultimate goal is because then perhaps you can offer an even better solution than using the formatter.
We are implementing a RESTful server with a partner. Their system (based on websphere) sends us perfectly standard JSON except that everything is enclosed in quotes. The standard formatter/parser does not miss a beat and happily converts all the incoming quoted values to dates, decimals, booleans, etc. We are not looking to change this behaviour.
The responses are also standard JSON but they also want all the values to be quoted. So in our data transfer object everything that is not either a child object or an array is a string and gets serialised correctly most of the time. But a further limitation is that all the properties that are null have to be treated differently to how most systems would treat them. Namely:
Null strings are passed as empty string. "property":"" and not "property":null
Null arrays are passed as empty arrays. "array":[] and not "array":null
Null child objects are passed as an empty object. "object":{} and not "object":null
And we are not allowed to simply omit them either. Not that that would be easy I suspect.
I hope that makes the requirement a little clearer. Our solution to use the formatter was based on another question Json Convert empty string instead of null and this works well for what it's worth but stumbles only because it tries to apply the rules in both directions.
You can write a custom MediaTypeFormatter to achieve what you need.
An official tutorial on how to write custom media-type formatters is available in this link http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters
Doing so will allow you to perform an http request using JSON and return a different media-type than JSON.
Keep in mind that when doing so the client needs to send the desired media-type on the request (in the accept header).
ICredentials credentials = CredentialCache.DefaultCredentials;
NetworkCredential credential = credentials.GetCredential(uri, "Basic");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Credentials = credential;
request.Method = "GET";
request.Headers.Add("api-version", "1.0");
request.Headers.Add("customer-code", code);
request.Headers.Add("Authorization", AuthUser);
request.ContentType = "application/json"; //The request is sent in JSON
request.Accept = "text/plain"; //You ask the server to return the response in the format you need it
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
Stream receiveStream = response.GetResponseStream();
YES - You can..
You can define 2 different implementation of MediaTypeFormatter. Set the properties CanReadType() & CanWriteType() as per your choice. Then implement WriteToStream() & ReadFromStream() in both formatters. Finally register both of them for your specific route.

Sending and receiving SOAP messages

I am writing a web service client in C# and do not want to create and serialize/deserialize objects, but rather send and receive raw XML.
Is this possible in C#?
Here is part of an implementation I just got running based on John M Gant's example. It is important to set the content type request header. Plus my request needed credentials.
protected virtual WebRequest CreateRequest(ISoapMessage soapMessage)
{
var wr = WebRequest.Create(soapMessage.Uri);
wr.ContentType = "text/xml;charset=utf-8";
wr.ContentLength = soapMessage.ContentXml.Length;
wr.Headers.Add("SOAPAction", soapMessage.SoapAction);
wr.Credentials = soapMessage.Credentials;
wr.Method = "POST";
wr.GetRequestStream().Write(Encoding.UTF8.GetBytes(soapMessage.ContentXml), 0, soapMessage.ContentXml.Length);
return wr;
}
public interface ISoapMessage
{
string Uri { get; }
string ContentXml { get; }
string SoapAction { get; }
ICredentials Credentials { get; }
}
You can use the System.Net classes, such as HttpWebRequest and HttpWebResponse to read and write directly to an HTTP connection.
Here's a basic (off-the-cuff, not compiled, non-error-checking, grossly oversimplified) example. May not be 100% correct, but at least will give you an idea of how it works:
HttpWebRequest req = (HttpWebRequest) HttpWebRequest.Create(url);
req.ContentLength = content.Length;
req.Method = "POST";
req.GetRequestStream().Write(Encoding.ASCII.GetBytes(content), 0, content.Length);
HttpWebResponse resp = (HttpWebResponse) req.getResponse();
//Read resp.GetResponseStream() and do something with it...
This approach works well. But chances are whatever you need to do can be accomplished by inheriting the existing proxy classes and overriding the members you need to have behave differently. This type of thing is best reserved for when you have no other choice, which is not very often in my experience.
Yes - you can simply declare the inputs and outputs as XmlNode's
[WebMethod]
public XmlNode MyMethod(XmlNode input);
You can have your web service method return a string containing the xml, but do heed the comment above about making things more error-prone.

Categories

Resources