Monday, July 2, 2018

Restore AJAX handling for ASP.NET Core to previous functionality

Leave a Comment

In previous MVC5 and below, you could make an ajax call that unwrapped the parameters properly:

JS:

$.post('/controller/endpoint',{intparam: 1, strparam: 'hello'}) 

CS:

public ActionResult endpoint(int intparam, string strparam){} 

In the new aspnetcore, it has changed:

CS:

public CustomClassWrapper{      public int intparam {get;set;}     public string stringparam {get;set;} } public ActionResult endpoint([FromBody]CustomClassWrapper item){} 

To sum it up, in the new framework, you need to write a wrapper class and can only pass one [FromBody] parameter to the method. Previously, the params would be unwrapped by variable name correctly.

So, i'm trying to re-implement this functionality in an aspnetcore middleware component. I'm having difficulty in how to accomplish calling the controller method properly with the parameters.

My current cut-down code:

public async Task Invoke(HttpContext context)         {             if (IsAjaxRequest(context.Request))             {                 try                 {                     string bodyContent = new StreamReader(context.Request.Body).ReadToEnd();                     var parameters = JsonConvert.DeserializeObject(bodyContent);                     ///What to do here?                 }                 catch (Exception ex)                 {                     throw new Exception("AJAX method not found ", ex);                 }             }             else             {                 await _next(context);             }         } 

I'm really just not sure about what to do after deserializing the parameters. I have the URL for the endpoint and also the params correctly. Just need to know how to call the method and return the result as JSON. Should i be using Reflection to get the controller method? Or is there a better way using MVC?

2 Answers

Answers 1

it's very simple thing i don't know why it not working at your end

JS

$.post('actionMethodURl', { FirstName: '1', LastName: 'hello' }).done(Successfunction); 

CS

[HttpPost] public ActionResult endpoint(string FirstName,string LastName) {   object Message = string.Empty;   if (ModelState.IsValid)    {      Message = "Pass";    }    else    {    Message = ModelState.Errors();    }    return Json(Message); } 

MyJSCode MyActionMetho

Answers 2

Try implement custom IModelBinder.

public class BodyFieldModelBinder : IModelBinder {     public Task BindModelAsync(ModelBindingContext bindingContext)     {         bindingContext.HttpContext.Request.EnableRewind(); // required to read request body multiple times         var inputStream = bindingContext.HttpContext.Request.Body;         if (inputStream.Position != 0L)             inputStream.Position = 0;         var bodyValue = new StreamReader(inputStream, Encoding.UTF8).ReadToEnd();         var jsonObject = (JObject)JsonConvert.DeserializeObject<object>(bodyValue);         if (jsonObject.TryGetValue(bindingContext.FieldName, out var jToken))         {             var jsonSerializer = JsonSerializer.Create();             var result = jToken.ToObject(bindingContext.ModelType, jsonSerializer);             bindingContext.Result = ModelBindingResult.Success(result);             return Task.CompletedTask;         }         bindingContext.Result = ModelBindingResult.Failed();         return Task.CompletedTask;     } } 

Be careful, the code above lacks error handling and etc.

And use it like this:

[HttpPost] public IActionResult Endpoint([ModelBinder(typeof(BodyFieldModelBinder))] int intparam) 

Also you could implement custom attribute to reduce complexity of declaration:

public class BodyFieldAttribute : ModelBinderAttribute {     public BodyFieldAttribute()         : base(typeof(BodyFieldModelBinder))     {     } } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment