Bryan Dellinger
Bryan Dellinger

Reputation: 5294

can I use FromBody and FromUri in .net MVC?

I have an asp.net MVC controller (not web api, not core) I am attempting a post that also has a uri variable. but I am receiving.

FromBody could not be found are you missing a using directive or assembly refrence

same for FromUri

using CFF.CareCenterPortal.BeInCharge.Services;
using CFF.CareCenterPortal.BeInCharge.ViewModels;
using CFF.CareCenterPortal.Web.Controllers.Portal;
using System;
using System.Web.Mvc;

namespace CFF.CareCenterPortal.Web.Controllers.BeInCharge
{
    [Authorize]
    [RoutePrefix("beincharge/caregiver")]
    public class BeInChargeCaregiverController : IdentityController
    {
        [HttpPost] 
        [Route("{id}")]
        public ActionResult EditCaregiver([FromBody()] CareGiverViewModel data, [FromUri()] int id)

        {
            var service = new BeInChargeDataService();
            var result = service.EditCaregiver(data,id,CurrentUser.NameIdentitifier);
            if (result == null)
            {
                return new HttpStatusCodeResult(System.Net.HttpStatusCode.InternalServerError, "An Unhandled Error Occcured");
            }

            if (!String.IsNullOrEmpty(result.Error) && !String.IsNullOrWhiteSpace(result.Error))
            {
                return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, result.Error);
            }

            return Json("Success");
        }

Upvotes: 4

Views: 13796

Answers (1)

Erik Philips
Erik Philips

Reputation: 54628

can I use FromBody and FromUri in .net MVC?

No. From what I understand, those attributes are only a WebAPI convention. Your options are to either use WebAPI Controller (very simple) or write your own Custom Model Binder for MVC that can inspect the parameter for attributes to mimic your needs.

I'm not sure you're aware, but the MVC ModelBinder already gets values from Route, QueryString and Body to materialize parameters.

You're welcome to look at the Source Code to MVC. The most important is the ValueProviderFactories, which has the following method:

    private static readonly ValueProviderFactoryCollection _factories 
      = new ValueProviderFactoryCollection()
    {
        new ChildActionValueProviderFactory(),
        new FormValueProviderFactory(),
        new JsonValueProviderFactory(),
        new RouteDataValueProviderFactory(),
        new QueryStringValueProviderFactory(),
        new HttpFileCollectionValueProviderFactory(),
        new JQueryFormValueProviderFactory()
    };

This is what MVC uses to provider values to the model binder.

Example:

I've taken the Default MVC website and made the following changes:

/views/home/Index.cshtml

line: 8:

    <p><a class="btn btn-primary btn-lg js-test">Learn more &raquo;</a></p>

Added to the bottom of the file:

<script src="https://code.jquery.com/jquery-3.3.1.min.js"
        integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
        crossorigin="anonymous"></script>
<script>
    $(document).ready(function () {
        $('.js-test').on('click', function () {
            $.ajax({
                url: '@Url.RouteUrl(new{ action="Name", controller="Home", id=5})',
                data: JSON.stringify({Name: 'My Test Name' }),
                    type: 'POST',
                    dataType: 'json',
                    contentType: "application/json",
            });
        })
    });
</script>

Added the following File:

/Models/Home/TestVM.cs

public class TestVM
{
    public string Name {  get; set; }
}

Updated the controller:

/Controllers/HomeController.cs:

    public ActionResult Name(TestVM test, int id)
    {
        System.Diagnostics.Debug.WriteLine(test.Name);
        System.Diagnostics.Debug.WriteLine(id);
        return new  EmptyResult();
    }

Now when the button is clicked, the following request is made:

Request URL: http://localhost:53549/Home/Name/5
Request Method: POST
Status Code: 200 OK
Remote Address: [::1]:53549
Referrer Policy: no-referrer-when-downgrade
Cache-Control: private
Content-Length: 0
Date: Tue, 03 Jul 2018 17:21:55 GMT
Server: Microsoft-IIS/10.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 23
Content-Type: application/json
Host: localhost:53549
Origin: http://localhost:53549
Pragma: no-cache
Referer: http://localhost:53549/

{Name: "My Test Name"}  
Name
:
"My Test Name"

My Debug window Prints:

My Test Name

5

The My Test Name is ModelBound from the JsonValueProviderFactory and the id which comes from the url http://localhost:53549/Home/Name/5 is ModelBound from the RouteDataValueProviderFactory.

Upvotes: 5

Related Questions