How can I get the raw JSON dictionary from ASP.NET MVC Web API post? - asp.net-mvc

With a ApiController subclass, it has the ability in Post method to bind it to an existing model object such as
public class RegisterController : ApiController
{
public void Post(Product product)
but if the incoming JSON data contains data that I'll use to create multiple model objects, how can I get to the data directly?
public void Post(dynamic value)
returns value as null. Is there an easy shorthand way of getting to it like request.POST['name'] or something?
Let's say the data looks like
{
'productID':1,
'productName':'hello',
'manufacturerID':1,
'manufacturerName':'world'
}

One option may be using one of the ReadAsAsync* methods in HttpContent instance off of the Request object
public void Post() {
var result = this.Request.Content.ReadAsAsync<string>().Result;
}
I don't know what format you're sending your data in, but you can retrieve it this way.
You could try this too for multiple objects...
public void Post(IEnumberable<Product> products) {
}

Related

Implementing data interface in ASP.NET MVC Controller and returning JSON

I would like to have my Controller implement my data interface that returns custom objects. All the objects are serializable and decorated by JSON attributes. So I would like to have my controller method simply be that:
public class MyController : Controller, IMyInterface
{
public Foo[] GetFoosByName(string name)
{
return new Foo[]{new Foo(name), new Foo(name)}
}
}
If I do it I get simply "Foo[]" response. What I'd like to get is JSON-serialized Foo objects.
I can easily achieve this by changing my response to be JsonResult:
public JsonResult GetFoosByName(string name)
{
return Json(new Foo[]{new Foo(name), new Foo(name)});
}
But then I won't be able to implement IMyInterface in the way that is easily maintainable.
Any ideas on how I can automatically get the behavior as I was returning JsonResult, but still keeping original return types?
Generally I would recommend against such a pattern. An MVC Controller should ideally be kind of a top-most layer, and I think it should not implement interfaces. You should implement such interfaces in a service layer, below the MVC Controllers.
However, if you still want to do it so, you can use explicit implementation like this.
public class MyController : Controller, IMyInterface
{
public JsonResult GetFoosByName(string name)
{
return Json(((IMyInterface)this).GetFoosByName(name));
}
Foo[] IMyInterface.GetFoosByName(string name)
{
return new[] { new Foo(name) };
}
}

How to handle a POST method that also has a parameter of unknown type?

I am coding to handle a Facebook callback. Facebook calls the same Url with POST but with different object types. I am not ready to handle all the parameter types, so I tried the following:
public void Post([FromBody]class1 webhook1)
{ // for object1
}
public void Post([FromBody]class2 webhook2)
{ // for object12
}
public async Task Post()
{
string rawData = await Request.Content.ReadAsStringAsync();
log(rawData);
}
However, I get this exception:
"Multiple actions were found that match the request ...
Is there a way to allow a fallback option for parameter types I am not ready to handle?
Method overloading based on the type of parameter is not supported for "web" routing methods
Use route attribute:
[Route("webhook1")]
public void Post([FromBody]class1 webhook1) {}
[Route("webhook2")]
public void Post([FromBody]class2 webhook2) {}
Or if you don't want client side to know about different parameter's types,
then make one "web" method where you read raw data from the body of request,
detect a type of data and call correspondent method to handle it
You may want to use attribute based routing instead as this gives you a lot more flexibility. Web api donot support standard routing methods well.
It should be something like this:
[RoutePrefix("api/example")]
public ExampleController : ApiController{
[Route("postwebhook1")]
public void Post([FromBody]class1 webhook1)
{ // for object1
}
[Route("postwebhook2")]
public void Post([FromBody]class2 webhook2)
{ // for object12
}
[Route("post")]
public async Task Post()
{
string rawData = await Request.Content.ReadAsStringAsync();
log(rawData);
}
}

Change returned object value after action execution in Web API

In ASP.Net Web API, the action returned object will be converted to XML or JSON automatically - is there a way to add additional process to the returned object before it gets converted?
What I want to achieve is to wrap returned object into a generic APIResponse (another class) type which has an object Property called Data that will be assigned with whatever the original returned object is.
for example:
public Books[] FindBooks(string keyword)
{
..
return new Books[] {new Book(){Name="ASP.NET"}};
}
This will return JSON of book array by default, however I want to wrap the result into an object called APIResponse, so the returned object becomes:
new APIResponse(){
Data = //the Book[] array return from the action method
}
By doing this, I will be able to keep the freedom of returning normal business objects in Web API however always return the same object type in JSON format when the front-end Ajax requests.
I believe it can be done in a way however I'm not familiar with the Web API life cycle, can any way give some guide on this?
Thank you.
I fixed it by creating a custom MediaTypeFormatter however simply inheriting from JSON formatter which have already got all what I need, here is the very simple code I added, which resolved all issues I have!!!
public class APIResponseMediaFomatter : JsonMediaTypeFormatter
{
public override Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
{
ResponseMessage wrappedValue = null;
if (type != typeof(ResponseMessage) || (value != null && value.GetType() != typeof(ResponseMessage)))
wrappedValue = new ResponseMessage(value);
return base.WriteToStreamAsync(typeof(ResponseMessage), wrappedValue, writeStream, content, transportContext);
}
}
Cheers!
Interestingly, Web API already works exactly how you describe. It already has generic request and response classes that can hold your object payload. Just do the following,
public HttpResponseMessage FindBooks(string keyword)
{
...
var books = new Books[] {new Book(){Name="ASP.NET"}};
var content = new ObjectContent<Book[]>(books,new JsonMediaTypeFormatter());
return new HttpResponseMessage { Content = content);
}
There is no need to re-invent your own generic response object that can hold metadata and data, HTTP has already done that for you.
Why dont you return your wrapper object APIResponse from WebAPI
public APIResponse FindBooks(string keyword)
{
var books = new Books[] {new Book(){Name="ASP.NET"}};
return new APIResponse {Data= books };
}
Just use an action filter, and modify the response content inside it:
public class ApiResponseWrapperActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
// Check that the response is an object content
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
// Wrap the returned value in the ApiResponse
objectContent.Value = new ApiResponse() { Data = objectContent.Value };
}
}
Apply the filter to the whole API (in global config) or a whole controller (attribute applied to the controller class) or to the desired methods (attribute in each method).
If you're returning something that it's not an object (a custom response) it will skip the wrapping.

Returning Json from an MVC controller that extends Apicontroller

I'm trying to return a Json string from an MVC controller in a WebAPI application, but am unable to use return Json(... because the class being used extends ApiController and not Controller (I believe).
Is there an alternative method to do what I'm trying to do (e.g. return a different type)? Or a workaround?
This is my controller code:
public class SocialController : ApiController
{
public ActionResult Get(SocialRequest request) // or JsonResult?
{
JavaScriptSerializer js = new JavaScriptSerializer();
string jsontest = js.Serialize(request); // just serializing back and forth for testing
return Json(jsontest, JsonRequestBehavior.AllowGet);
}
}
The error I'm receiving is "System.Web.Helpers.Json is a type but is used like a variable."
I've found the following related SO question but it hasn't solved it for me, if anyone can elaborate I'd really appreciate it (and dish out the rep points):
Why Json() Function is unknown
In Asp.net Web Api you don't have ActionResults anymore. You simply return the object you need. The framework converts the object to the proper response (json, xml or other types)
[HttpGet]
public IEnumerable<string> GetUsers(SocialRequest request)
{
return _applicationsService.GetUserss(request);
}

Binding application/json to POCO object in asp.net mvc, Serialization exception

I'm passing json back up from my view to my controller actions to perform operations. To convert the json being sent in, to a POCO I'm using this Action Filter:
public class ObjectFilter : ActionFilterAttribute {
public Type RootType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext) {
IList<ErrorInfo> errors = new List<ErrorInfo>();
try {
object o = new DataContractJsonSerializer(RootType).ReadObject(filterContext.HttpContext.Request.InputStream);
filterContext.ActionParameters["postdata"] = o;
}
catch (SerializationException ex) {
errors.Add(new ErrorInfo(null, ex.Message));
}
finally {
filterContext.ActionParameters["errors"] = errors.AsEnumerable();
}
}
It's using the DataContractJsonSerializer to map the JSON, over to my object. My Action is then decorated like so:
[ObjectFilter(RootType = typeof(MyObject))]
public JsonResult updateproduct(MyObject postdata, IEnumerable<ErrorInfo> errors) {
// check if errors has any in the collection!
}
So to surmise, what is going on here, if there is a problem serializing the JSON to the type of object (if a string cannot be parsed as a decimal type or similar for eg), it adds the error to a collection and then passes that error up to the view. It can then check if this collection has an errors and report back to the client.
The issue is that I cannot seem to find out which field has caused the problem. Ideally I'd like to pass back to the view and say "THIS FIELD" had a problem. The SerializationException class does not seem to offer this sort of flexibility.
How would the collective SO hivemind consider tackling this problem?
I would just do an ajax form post. It's much easier.
http://plugins.jquery.com/project/form
http://malsup.com/jquery/form/
How about this: Json.Net
It reads a JSON string and then Deserialises it to the given POCO object.
string jsonResult = GetJsonStringFromSomeService();
MyPocoObject myobject = JsonConvert.DeserializeObject<MyPocoObject>(jsonResult);
Console.Write("Damn that is easy");
But for the determing where errors occur, I am not too sure.

Resources