Cover with unit test WebRequest c# - 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.

Related

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);
}

Issues passing an Xml file to a method in console application

I am working on a c# console application where I am making a Http Post request to a web api by using xml file and I'm kind of new to XML and web services but I figured out the following code for the request but failed to pass xml data to the method
static void Main(string[] args)
{
string desturl=#"https://xyz.abcgroup.com/abcapi/";
Program p = new Program();
System.Console.WriteLine(p.WebRequestPostData(desturl, #"C:\Applications\TestService\FixmlSub.xml"));
}
public string WebRequestPostData(string url, string postData)
{
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
req.ContentType = "text/xml";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(postData);
req.ContentLength = bytes.Length;
using (Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
using (System.Net.WebResponse resp = req.GetResponse())
{
if (resp == null) return null;
using (System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()))
{
return sr.ReadToEnd().Trim();
}
}
}
For obvious reasons the above code throws 404 error as I think I am not passing the xml data properly
May I know how I can fix this?
You're not posting xml, your posting the string C:\Applications\TestService\FixmlSub.xml
Change your method call from:
System.Console.WriteLine(p.WebRequestPostData(desturl, #"C:\Applications\TestService\FixmlSub.xml"));
to
var xml = XElement.Load(#"C:\Applications\TestService\FixmlSub.xml");
System.Console.WriteLine(p.WebRequestPostData(desturl, xml.ToString(SaveOptions.DisableFormatting));
If you are trying to learn post / receive, go for it. But there are open source libraries that are already well tested to use if you want to use them.
The non-free version of Servicestack.
And their older free-version. I think the older free version is great. I've never tried the newer one. You deal with objects, like say an Employee and pass that to the library and it does the translation to xml or whatever the web-service wants.
You can post whole strings if you want. They have great extension methods to help you with that too.

HttpWebRequest and Response

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

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.

Problems consuming WebService in .Net (ReCaptcha)

I am having difficulty in consuming the reCaptcha Web Service using C#/.Net 3.5. Although I think the problem is with consuming web services in general.
String validate = String.Format("http://api-verify.recaptcha.net/verify?privatekey={0}&remoteip={1}&challenge={2}&response={3}", PrivateKey, UserIP, Challenge, Response);
WebClient serviceRequest = new WebClient();
serviceRequest.Headers.Add("ContentType","application/x-www-form-urlencoded")
String response = serviceRequest.DownloadString(new Uri(validate ));
It keeps telling me that the error is: nverify-params-incorrect. Which means:
The parameters to /verify were incorrect, make sure you are passing all the required parameters.
But it's correct. I am using the private key, the IP address (locally) is 127.0.0.1, and the challenge and response seem fine. However the error keeps occurring.
I am pretty sure this is a issue with how I am requesting the service as this is the first time I have actually used webservices and .Net.
I also tried this as it ensures the data is posted:
String queryString = String.Format("privatekey={0}&remoteip={1}&challenge={2}&response={3}",PrivateKey, UserIP, Challenge, Response);
String Validate = "http://api-verify.recaptcha.net/verify" + queryString;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(Validate));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = Validate.Length;
**HttpWebResponse captchaResponse = (HttpWebResponse)request.GetResponse();**
String response;
using (StreamReader reader = new StreamReader(captchaResponse.GetResponseStream()))
response = reader.ReadToEnd();
Seems to stall at the point where I get response.
Any advice?
Thanks in advance
Haven't worked with the recaptcha service previously, but I have two troubleshooting recommendations:
Use Fiddler or Firebug and watch what you're sending outbound. Verifying your parameters would help you with basic troubleshooting, i.e. invalid characters, etc.
The Recaptcha Wiki has an entry about dealing with development on Vista. It doesn't have to be limited to Vista, though; if you're system can handle IPv6, then your browser could be communicating in that format as a default. It appears as if Recaptcha deals with IPv4. Having Fiddler/Firebug working would tell you about those other parameters that could be causing you grief.
This may not help solve your problem but it might provide you with better troubleshooting info.
So got this working, for some reason I needed to write the request to a stream like so:
//Write data to request stream
using (Stream requestSteam = request.GetRequestStream())
requestSteam.Write(byteData, 0, byteData.Length);
Could anyone explain why this works. I didn't think I would need to do this, don't completely understand what's happening behind the scenes..
Damien's answer is correct of course, but just to be clear about the order of things (I was a little confused) and to have a complete code sample...
var uri = new Uri("http://api-verify.recaptcha.net/verify");
var queryString = string.Format(
"privatekey={0}&remoteip={1}&challenge={2}&response={3}",
privateKey,
userIP,
challenge,
response);
var request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Post;
request.ContentLength = queryString.Length;
request.ContentType = "application/x-www-form-urlencoded";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(queryString);
}
string result;
using (var webResponse = (HttpWebResponse)request.GetResponse())
{
var reader = new StreamReader(webResponse.GetResponseStream());
result = reader.ReadToEnd();
}
There's a slight difference in that I'm writing the post variables to the request, but the core of it is the same.

Categories

Resources