Tag Archives: Controller

Asp.Net Core 2.0 – Passing data into a Model Using DI

Imagine you have an Asp.Net Core web page, and you would like to edit some data in a form, but you’d like to default that data to something (maybe initially specified in the Web.Config).

I’m sure there’s dozens of ways to achieve this; but this is one.

Let’s start with a bog standard MVC web app:

Step one is to define a model in which to hold your data; here’s mine:

public class CurrentAppData
{
    public string DataField1 { get; set; }
}

Let’s register that in the IoC container:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });
 
 
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
 
    services.AddTransient<CurrentAppData, CurrentAppData>(
        a => new CurrentAppData()
        {
            DataField1 = "test value"
        });

Next thing we’ll need is a View, and a corresponding view model to edit our data; here’s the view:

@model EditDataViewModel
@{
    ViewData["Title"] = "Edit Data";
}
 
<h2>@ViewData["Title"]</h2>
 
<div>
    <label>Change data here:</label>
    <input type="text" asp-for="EditData.DataField1" />
 
</div>

And now the view model (that is, the model that is bound to the view):

public class EditDataViewModel
{
    public EditDataViewModel(CurrentAppData editData)
    {
        EditData = editData;
    }
    public CurrentAppData EditData { get; set; }
}

The final step here is to adapt the controller so that the CurrentAppData object is passed through the controller:

public class EditDataController : Controller
{
    private readonly CurrentAppData _currentAppData;
 
    public EditDataController(CurrentAppData currentAppData)
    {
        _currentAppData = currentAppData;
    }
 
    public IActionResult EditData()
    {
        return View(new EditDataViewModel(_currentAppData));
 
 
    }
}

That works as far as it goes, and we now have the data displayed on the screen:

The next step is to post the edited data back to the controller; let’s change the HTML slightly:

<form asp-action="UpdateData" asp-controller="EditData" method="post" enctype="multipart/form-data">
    <label>Change data here:</label>
    <input type="text" asp-for="EditData.DataField1" />
    <br />
    <button type="submit" class="btn-default">Submit Changes</button>
</form>

We’ve added a submit button, which should cause the surrounding form element to execute whichever “method” it’s been told to (in this case, POST). It will look for an action on the controller called UpdateData, so we should create one:

public IActionResult UpdateData(EditDataViewModel editDataViewModel)
{
    System.Diagnostics.Debug.WriteLine(editDataViewModel.EditData.DataField1);
    return View("EditData", editDataViewModel);
}

Here, we’re accepting the EditDataViewModel from the view. However; when we run this, we get the following error:

Error:

InvalidOperationException: Could not create an instance of type ‘WebApplication14.Models.EditDataViewModel’. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the ‘editDataViewModel’ parameter a non-null default value.

Let’s first implement a fix for this, and then go into the whys and wherefores. The fix is actually quite straightforward; simply give the view model a parameterless constructor:

public class EditDataViewModel
{
    public EditDataViewModel()
    {
        
    }
 
    public EditDataViewModel(CurrentAppData editData)
    {
        EditData = editData;
    }
    public CurrentAppData EditData { get; set; }
}

The problem that we had here is that the `EditDataViewModel` that is returned to UpdateData is a new instance of the model. We can prove this by changing our code slightly:

Here, we’ve added a field called TestField1 to the model, and populated it just before we pass the model to the view; and on the post back, it’s gone. I’m not completely sure why the view model can’t be created by the middleware in the same way that the controller is; but that’s the subject of another post.

Finally, show the value back to the screen

To wrap up, we’ll just show the same value back to the screen; we’ll add an extra value to the model:

public class CurrentAppData
{
    public string DataField1 { get; set; }
 
    public string DisplayField1 { get; set; }
}

And we’ll just display it in the view:

<form asp-action="UpdateData" asp-controller="EditData" method="post" enctype="multipart/form-data">
    <label>Change data here:</label>
    <input type="text" asp-for="EditData.DataField1" />
    <br />
    <button type="submit" class="btn-default">Submit Changes</button>
    <br />
    <label>@Model.EditData.DisplayField1</label>
    <br />
</form>

Finally, we’ll copy that value inside the controller (obviously, this is simulating something meaningful happening), and then display the result:

public IActionResult UpdateData(EditDataViewModel editDataViewModel)
{
    editDataViewModel.EditData.DisplayField1 = editDataViewModel.EditData.DataField1;
    return View("EditData", editDataViewModel);
}

Let’s see what that looks like:

Web API Routing – The Basics

Working with API projects, it’s easy to miss some key rules about the routing. This post is basically the result of some that I missed, and subsequent the investigation. It covers some very basic routing rules, and it certainly not intended to be an exhaustive guide.

.Net Framework

Starting with a .Net Framework Web API, let’s create a new web app:

And add a new controller:

Here’s the code for the controller; as you will see, it’s massively complex, but the good news is that you only need to pay attention to the name of the action, and the code inside it:

public class TestController : ApiController
{
    [HttpGet]
    public IHttpActionResult TestAction()
    {
        return Ok("TestAction Performed");
    }
}

Let’s run the project and navigate to the URL:

How did I know that was the URL? It’s magic, and you can buy some of that magic by sending a cheque for the low, low price of $25 to the address shown at the bottom of the screen.

Actually, it’s defined in WebApiConfig.cs:

Parameters

Where there is more than a single function, one surprising (to me) feature is that the parameters that it accepts is more important to the routing than the name of the controller. Here’s a second action with a parameter:

[HttpGet]
public IHttpActionResult TestAction2(string test)
{
    return Ok("TestAction2 Performed");
}

… and here’s it working:

However, should I not give it the parameter that it craves, it hides away, and instead, we get the first function that’s no too fussy about parameters:

It doesn’t even matter whether I just put some drivel as the controller name; the first criteria is the parameter:

This is because, according to this it follows these criteria:

The default implementation is provided by the ApiControllerActionSelector class. To select an action, it looks at the following:
• The HTTP method of the request.
• The “{action}” placeholder in the route template, if present.
• The parameters of the actions on the controller.

So, if we add the {action} placeholder, that ensures that it uses the correct method:

public static void Register(HttpConfiguration config)
{
    // Web API configuration and services
 
    // Web API routes
    config.MapHttpAttributeRoutes();
 
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        //routeTemplate: "api/{controller}/{id}",
        routeTemplate: "api/{controller}/{action}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

Otherwise, we get a best guess based on the parameters.

.Net Core Web API

The rules have changed since switching to .Net Core; WebApiConfig has gone and, in its place, it a localised routing system.

Here, you tell the class how to handle routing; for example, the following:

[Route("api/[controller]")]

Will result anything decorated with HttpGet being called when the controller is called. The parameters must be explicitly decorated; so passing no parameters would look like this:

[HttpGet]
public string OneTest()
{
    return "TestOne";
}

Whereas, a single parameter would look like this:

[HttpGet("{id}")]
public string aaa(int id)
{
    return "value aaa";
}

If you duplicate the signatures then they are not found. As with the framework version, you can simply tell it to look to the action name that you give it:

[Route("api/[controller]/[action]")]
public class TestController : Controller
{
    [HttpGet]
    public IEnumerable<string> TestActionOne()
    {
        return new string[] { "one value1", "value2" };
    }
 
    [HttpGet]
    public string TestActionTwo()
    {
        return "two value";
    }

But, again, it pays no attention to parameters until you decorate it correctly.

References

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing

Mocking IPrinciple.Identity and Claims in NSubstitute

In ASP.Net, there is a concept of an identity. Built on top of this is an authentication system based on claims; allowing applications to implement a claims based authentication system. That is, I can determine if my user has “Administrator” privileges in the following syntax:

var claim = ClaimsIdentity.FindFirstValue("Administrator");

For more information about how claims work, see this excellent explanation. This post is not really concerned with how claims work, but rather, how to mock them out; which is much more difficult than you might guess.

In the references below, you’ll see a number of different strategies to mock out the claims and principle objects. There also seems to be a loose consensus that even attempting to do this is folly. However, I’ve cobbled together a set of mocks using NSubstitute that work. I’m not claiming that they work in all cases, or that they will work in any situation other than the specific one that I am trying to solve; but it did work for that, and so I thought it useful enough to share.

var myController = new MyController();
 
var mockClaim = new Claim("Administrator", "test");
 
var identity = Substitute.For<ClaimsIdentity>();
identity.Name.Returns("test");
identity.IsAuthenticated.Returns(true);
identity.FindFirst(Arg.Any<string>()).Returns(mockClaim);
 
var claimsPrincipal = Substitute.For<ClaimsPrincipal>();
claimsPrincipal.HasClaim(Arg.Any<string>(), Arg.Any<string>()).Returns(true);
claimsPrincipal.HasClaim(Arg.Any<Predicate<Claim>>()).Returns(true);
claimsPrincipal.Identity.Returns(identity);
 
var httpContext = Substitute.For<HttpContextBase>();            
httpContext.User.Returns(claimsPrincipal);
 
var controllerContext = new ControllerContext(
    httpContext, new System.Web.Routing.RouteData(), myController);           
 
myController.ControllerContext = controllerContext;
 
// Act
var result = myController.TestMethod();
 
// Assert
// . . .

Remember that this is only necessary if you are trying to access claims based on the identity within the `TestMethod()`. Also, I’ll remind the reader that I assert only that this worked in the specific situation that I needed it to, but it’s probably a good starting point for others.

References

https://volaresystems.com/blog/post/2010/08/19/Dont-mock-HttpContext

http://nsubstitute.github.io/help/set-return-value/

https://stackoverflow.com/questions/1389744/testing-controller-action-that-uses-user-identity-name

https://stackoverflow.com/questions/13579519/mock-authenticated-user-using-moq-in-unit-testing

https://stackoverflow.com/questions/14190066/is-there-any-way-i-can-mock-a-claims-principal-in-my-asp-net-mvc-web-application

https://stackoverflow.com/questions/22762338/how-do-i-mock-user-identity-getuserid/23960592

https://dotnetcodr.com/2013/02/11/introduction-to-claims-based-security-in-net4-5-with-c-part-1/