How do I get the parameter values from in a web service - asp.net

I have a web service (an ASP.NET .asmx page), and for debugging purposes I need to log all calls to the webservice, including values of all parameters passed into each call. So basically the first thing each WebMethod should do is log it's state with details of all the parameter values passed in to it.
So far so good. The complication is that I also want an automated way of getting the parameter values - there's quite a few webmethods with different signatures, and some of them have up to ~30 parameters, so manually coding against each specific parameter would likely be massively error-prone. I'd rather be able to call a method that looks at the current Http context and automatically uses that to grab and parse whatever has been passed in by the client.
But I hit a snag. When I look at HttpContext.Current.Request, it turns out that both the Form and QueryString collections are empty. So if the arguments passed to the webmethod aren't in either of those collections, where would they be? Anyone know how I can retrieve them?

You can use AOP techniques for this task. Considering PostSharp, you can create custom aspect like this:
[Serializable]
public class TraceAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Trace.WriteLine(string.Format("Entering {0}", args.Method.Name));
for (int i = 0; i < args.Arguments.Count; i++)
{
Trace.WriteLine(string.Format(" {0}", args.Arguments.GetArgument(i)));
}
}
}
and then apply it to your web-service methods:
[WebMethod, Trace]
public string HelloWorld()
{
return "Hello World";
}

You could use SOAP extensions and follow the example in this post to log the request which would have the method name and parameters.

SOAP Extentions is a better choice. Here is another example to retreive SOAP request and SOAP response as XML. All you do is parse the XML to retreive parameter name value pairs.

Related

ASP.NET return Http Response from function called outside controller

I just started working with asp.net mvc and am working on a legacy codebase with controllers that all have the same validation code at the front of every controller. (ie. multiple lines of the exact same code returning if the user id/key are not correct)
Is there any way to separate this out into an external function that can return an HTTP response immediately if validation fails?
Right now I can do something like this:
if (!validate()) {
return forbid("Your un or Password is incorrect");
}
or for a more specific message:
var errorMsg = validate();
if (errorMsg) {
return forbid(errorMsg);
}
but if I'm going to put this at the front of most of my controllers, I'd rather have a one-liner that I takes up as little room as possible. Is there an option for bypassing the rest of the controller function and returning an HTTP response from inside my validate() function? Or is there possibly a more appropriate way to do this?

ASP.NET Web API - method that is called for all requests prior to the routed method?

I'm writing in C# for ASP.NET Web API 2. What I want is a catch-all method that will execute for every single request that comes to my Web API.
If the method returns null, then the original routing should continue, seeking out the correct method. However, if the method returns, say, an HTTPResponseMessage, the server should return that response and not proceed on to normal routing.
The use case would be the ability to handle various scenarios that may impact the entire API. For example: ban a single IP address, block (or whitelist) certain user agents, deal with API call counting (e.g. someone can only make X requests to any API method in Y minutes).
The only way I can imagine to do this right now is to literally include a method call in each and every new method I write for my API. For example,
[HttpGet]
public HttpResponseMessage myNewMethod()
{
// I want to avoid having to do this in every single method.
var check = methodThatEitherReturnsResponseOrNull(Request);
if (check != null) return (HttpResponseMessage)check;
// The method returned null so we go ahead with normal processing.
...
}
Is there some way to accomplish this in routing?
This is what Action Filters are for. These are Attributes that you can place either globally, at the class (Controller), or at the method (Action) levels. These attributes can do preprocessing where you execute some code before your action executes or post processing where you execute code after the action executes.
When using pre processing you have the option to return a result to the caller and not have your method (action) be fired at all. This is good for model validation, authorization checks, etc.
To register a filter globally edit the WebApiConfig.cs file.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new YourFilterAttribute()); // add record
// rest of code
}
}
To create a custom attribute inherit from System.Web.Http.Filters.ActionFilterAttribute or you can implement interface System.Web.Http.Filters.IActionFilter or you can implement IAuthorizationFilter/AuthorizationFilterAttribute if you specifically want to allow/deny a request.
It also sounds like you want to create multiple attributes, one for each role like IP filtering or count calling etc. That way it would be more modular instead of one enormous authorization filter.
There are many tutorials out there like this one (chosen at random in my Google search results). I am not going to post code because you did not do so either so I would just be guessing as to what you wanted to do.

How to make a controller accept post data from the body as well as URL in MVC 6 ASP.NET 5

Currently I am trying to write a controller in MVC 6 that is capable of accepting data from a post request. The issue is that depending on the client (which is not always a web browser), the data can come in as either key value pairs in the request URL, or as JSON in the request body.
Currently this method works for accepting the data from the URL:
[HttpPost]
public async Task<CaptureResponse> CaptureData(CaptureInfo capture) {
...
}
After a lot of trial and error (and stack overflow answers), I figured out that the [FromBody] attribute tells the model binder to look in the request body, which is required now because MVC 6 combines WebApi and standard MVC together. The following code parses data from JSON in the form body:
[HttpPost]
public async Task<CaptureResponse> CaptureData([FromBody] CaptureInfo capture) {
...
}
For simplicity, I would like to combine the two together somehow, so the model binder gives me the data in the same parameter variable. So far, the only way I can get the data into the same Action is to specify two parameters, one for the URL and one for the body, and do some null checking on each like so:
[HttpPost]
public async Task<CaptureResponse> CaptureData(CaptureInfo capture, [FromBody] CaptureInfo bodyCapture) {
if (bodyCapture != null) {
if (bodyCapture.RequiredProperty1!= null
&& bodyCapture.RequiredProperty2!= null) {
capture = bodyCapture;
}
}
...
}
I have tried specifying multiple properties before the input attribute like this:
[HttpPost]
public async Task<CaptureResponse> CaptureData(CaptureInfo [FromQuery][FromRoute][FromForm][FromBody] capture) {
...
}
But it does not work. Any ideas if something like this is possible?
As far as I know, it is just not possible. Of course you can try using workarounds, basically doing all request parsing yourself. It doesn't sound good, does it?
If you really want the things your way, I believe the best approach is to have two distinct endpoints in the controller and the private method for actual processing. Or, perhaps, even extract that method into an additional abstraction layer with BlaBlaService (CaptureService in your case, probably) class(es) responsible for all the dirty work. Sometimes it makes sense to separate your controllers layer from business logic - for example, for testing purposes.
PS: Your idea is quite similar to what was the approach in good old .NET & PHP times, and believe me, this particular idea is not the one that made those times good. You know, the MVC is much about the REST-like approach, so each endpoint of your controller is supposed to be dedicated to its own single function and obey to a single and uniform "intuitive" protocol.
The "intuitive" way to submit data to POST request for developers acquainted with REST is through the request body. I suggest you to consider going with this approach as the only one.
You need use Request.Form
like:
string username = HttpContext.Current.Request.Form.GetValues("key1")[0].ToString();
string password = HttpContext.Current.Request.Form.GetValues("key2")[0].ToString();
string something = HttpContext.Current.Request.Form.GetValues("key3")[0].ToString();

Web API Complex Data in Get

I am using Web APi, as I am new to this, I dont know much about it.
I am trying to implement search, as of now I am starting with only text search, but later there may be huge search criteria. for one text that is easy, as web api works good with
primitive data types. Now I want to create a class of filter, say the pagenumber , the pagesize also all the search criteria, so I created a class. I have created a MVC application which is communicating with the web api, the web api returns Json data, then I de-serialize it to model. I am stuck with the complex object part, also as of now I am using a list to get the data, later that will be replaced by data base. Following is the code.
public IEnumerable<Document> Get(PaggingDetails request) //public async Task<IEnumerable<Note>> GetNotes() for Async (DB)
{
return _repository.GetAll(pagedetails.PageNumber, pagedetails.PageSize, pagedetails.PageFilter);
//return await db.Notes.ToListAsync<Note>(); for async
}
public string GetPage(int pagenumber,int pagesize,string pagefilter)
{
try
{
PaggingDetails PageDetails = new PaggingDetails();
PageDetails.PageFilter = pagefilter;
PageDetails.PageSize = pagesize;
PageDetails.PageNumber = pagenumber;
return new System.Net.WebClient().DownloadString
("http://.../api/Document/?pagedetails=" +
PageDetails);
//new HttpClient().GetStringAsync("http://localhost:18545/api/Emails"); for async
//also pass parameters
}
catch (Exception ex)
{
}
return "";
}
By deafult, you cannot use a class as the type of parameter of a GET Web API action. You need to use individual parameters of single types.
If you want to use a class as parameter nothing stops you to use a POST action, in which you can include the data without any problem.
However you can force a complex parameter of a GET action to be read from the URI by decorating the comples attribute with [FromUri].
You can read this document to better understand Web API parameter binding:
Parameter Binding in ASP.NET Web API
By default, Web API uses the following rules to bind parameters:
If the parameter is a “simple” type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string. (More about type converters later.)
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
This is the standard way of working. If you use the [FromUri] attribute, the action selector won't be able to choose between different Get methods that receive different complex types. If you use a route with controller and action segments, you won't have that problem, becaus ethe actions selector will choose by action name, no matter what the aprameters are.
I don't like using the [FromUri] for this reason, and beacuse it's not the natural way to work with the GET action. But you can use it with the necessary precautions.

How to create a simple ASP.NET MVC action method that accepts HTTP-POST data?

i wish to have a simple Action in my controller that accepts a few optional values and some integer values.
this is my route i wish to have:
HTTP.POST
/review/create
and this is the Action method i would like...
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult Create(int userId,
int addressId,
byte baseScore,
byte reviewType,
string subject,
string description)
{ ... }
I'm under the uneducated impression that all of those arguments above will be populated by the forms collection values ... but it's not happening. Also, I have no idea how I would write a route, to handle those ... because those values are form post data....
here's my global.asax....
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Api - Search methods.
routes.MapRoute(
"Search Methods",
"{controller}/{action}"
);
In fact, the action method is never called because it doesn't seem to find it :(
But, if create and action without any of those arguments, then it finds it ?????????
How would you write a route and action method to accept some require and some optional arguments, for the route /review/create ?
As far as i can see you may rewrite your controller action like this:
public ActionResult Create(int foo, int bar, byte blah, string name, int? xxx) {
// code here
}
The ModelBinder will then ensure that foo,bar and blah are set. Name and xxx may be null. I can't test it a the moment, but i think return type of the action should be ActionResult.
If you are POST'ing a form, just make sure that the elements in your form (textboxes, checkboxes, textarea, etc) have id's that match the parameters in your method. As an alternative you can pass a FormCollection to the method, and do myFormCollection["foo"] to get a string representation of the value (which can then be parsed to an int).
From my experience, you are missing a number of key elements and concepts with this question.
First and foremost, I don't believe you can execute a POST without a form. The form has to contain the controls from which you pull the values that get passed to the controller method. If the goal is to simply unit test your POST controller method, then just call the method directly in your test, which it appears that you're doing, based on one of your comments. If you involve the view, then you're doing integration testing, not unit testing. Regardless of the test type, the test will always fail because you are choosing not to build the form. Even if you manage to force the POST using Fiddler, Firebug or any other mechanism, you're still not testing the view, you're testing the HTTP protocol.
I highly recommend that you employ a web application testing tool, such as WatiN or Selenium, to test your web pages, rather than throw together a quick-and-dirty test that really doesn't test anything useful.
In your post request set content-type="application/json; charset=UTF-8" and pass the values for the method parameter in JSON format. This should make Asp.MVC not to look in FormCollection for those values.

Resources