ASP.NET Core 2: Model Validation Part 2

download.jpgIn Part 1, we covered simple model validation where the entire model is posted back in a form.

In this tutorial, we cover how to validate just one field on the server as well.

Create a simple Model, on this class we have a National ID field. The possible values for this ID are too many to store or calculate on the client so need to be verified on the server without posting the entire form back.

public class PersonModel
{
    [Remote"VerifyNationalID""Home")] 
    public int NationalID { getset; }
}

On the Controller add a VerifyNationalID method on the Home controller:

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View(new PersonModel());
    }
 
    public IActionResult VerifyNationalID(int nationalId)
    {
        if (nationalId == 12345) return new JsonResult(true);
        return new JsonResult("That ID does not exist in the database");
    }

On the client add a simple text box and submit button. Use the TagHelpers to connect to the model’s NationalID field

<!-- Add the validation scripts-->
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.2.0.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.16.0/jquery.validate.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"></script>
 
 
<form action="/Home/VerifyEntireForm" method="post">
    <div class="form-group">
        <label asp-for="NationalID" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="NationalID" class="form-control" />
            <span asp-validation-for="NationalID" class="text-danger"></span>
        </div>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</form>

When run, a warning will appear when the user leaves the field. The plumbing is handled by jQuery and ASP.NET CORE.

validation2.png

 

 

ASP.NET Core 2: Model Validation Part 1

download.jpgIn this tutorial, we’ll show you how to add some simple custom business logic to a model so that values can be verified on the server via a post back.

Business Logic: Only children are allowed in this model. A child is under 13.

Our Model is simple and has a ChildOnly attribute which we’ll create next:

public class PersonModel
{
    [ChildOnly] 
    public int Age { getset; }
}

Next we create the business logic-holding attribute. The function IsValid() is what is called by ASP.NET Core’s validation system and is fairly simple:

public class ChildOnlyAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        //Get the model we are trying to validate
        if (validationContext?.ObjectInstance is PersonModel model)
        {
            //Only Kids are allowed (under 13)
            if (model.Age > 12)
            {
                return new ValidationResult("Person is too old and is not considered a child");
            }
        }
        return ValidationResult.Success;
    }
}

Now that we have the model and the business logic ready on the server, let’s add some simple HTML. The TagHelpers will convert the purple commands into properly bound HTML.

<form action="/Home/Verify" method="post">
    <div class="form-group">
        <label asp-for="Age" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="Age" class="form-control" />
            <span asp-validation-for="Age" class="text-danger"></span>
        </div>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</form>

On our controller we have the Actions to both present the form and verify it on a post back.

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View(new PersonModel());
    }
 
    public IActionResult Verify(PersonModel model)
    {
        if (!ModelState.IsValid)
        {
            return View("Index",model);
        }
        return new ContentResult()
        {
            Content = "Looks Good"
        };
    }

Here’s what it looks like when run:

home verify.png

 

ASP.Net Core 2: TagHelper Part 3: Custom html attributes

tag 3 logo.pngIn Part 1 you learned how to create a simple email TagHelper for ASP.Net Core. We will expand on that project and add a TagHelper which will add values to the html class attribute of any div.

Our goal is to write this in our Razor pages:
<div asp-button=“true”>My Button</div>

and have this Html created:
<div class=“btn btn-primary”>My Button</div>

Step 1: Using the project you wrote in Part 1 or Part 2, add a new class called ButtonTagHelper.cs

/// <summary>
/// Only Divs with the attribute asp-button are affected
/// </summary>
[HtmlTargetElement("div", Attributes = "asp-button")]
public class ButtonTagHelper : TagHelper
{
    /// <summary>
    /// The asp-button attribute will get auto-mapped to this property
    /// </summary>
    [HtmlAttributeName("asp-button")]
    public string Button { getset; }
 
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        //If there was an asp-button attribute add a bootstrap btn class
        if (this.Button == "true")
        {
            //Get the current value of the class attribute
            var currentClassValue = "";
            if (output.Attributes.ContainsName("class"))
            {
                currentClassValue = output.Attributes["class"].Value.ToString();
                output.Attributes.Remove(output.Attributes["class"]);
            }
 
            //Add a new class attribute with the previous values
            output.Attributes.Add("class""btn btn-primary " + currentClassValue);
        }
    }
}

Let’s break this down:

[HtmlTargetElement(“div”, Attributes = “asp-button”)]

This tells ASP.NET Core that the following TagHelper is to be applied to an div with an asp-button attribute.

[HtmlAttributeName(“asp-button”)]
public string Button { get; set; }

A bit of magic here. ASP.NET Core will convert the value of the asp-button attribute and will add it to the property. The property must be public.


Here’s the result:

taghelper3.png

ASP.Net Core 2: TagHelper Part 2: Display downloaded Quotes

quote-clipart-9TpbXMnnc.pngIn Part 1 you learned how to create a simple email TagHelper for ASP.Net Core. We will expand on that project and add a TagHelper.


Step 1: Add a new class called RandomQuoteTagHelper to your web project

public class RandomQuoteTagHelper :TagHelper
{
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        //The Html Tag will be a div
        output.TagName = "div";
 
        var html = "";
        using (var w = new WebClient())
        {
            //Get a random QUOTE
            var url = "http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1";
 
            //Convert the quote to a dynamic object so we can get the Quote text out
            dynamic quote = JsonConvert.DeserializeObject(w.DownloadString(url));
            html = quote[0].content;
        }
        //Add Html quote to the Div
        output.Content.SetHtmlContent(html);
    }
}

Step 2: Add the Tag Helper to a view

<random-quote></random-quote>

 


Here’s how it looks when run:

taghelper2.png

ASP.NET Core 2: TagHelpers Part 1

images.jpgTagHelpers let you simplify the markup in your Razor pages and improve readability.

Which would you rather have on your Razor Page?

<email-support></email-support>

or

taghelper1.png

Step 1: Create a new ASP.NET Core project, any template will do. Call it TagThis

Step 2: Add a class called EmailSupport.cs to the web project

This class tells ASP.NET Core how to render the custom tag and is fairly self-explanatory in this basic example

public class EmailSupport :TagHelper
{
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        //The Html Tag will be an Anchor
        output.TagName = "a";
 
        //Add the link and css class to the anchor tag
        output.Attributes.Add(new TagHelperAttribute("href","mailto:Support@IanVink.com"));
        output.Attributes.Add(new TagHelperAttribute("class""btn btn-primary"));
 
        //Add text to the link
        output.Content.SetHtmlContent("Email Support");
    }
}

Step 3: Edit the _ViewImports.cshtml file and tell it to add all Tag Helpers from the TagThis assembly. Notice the “*”

@addTagHelper *, TagThis

Step 4: Add Bootstrap and FontAwesome css to your _Layout.cshtml to make it look pretty

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" >
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

Step 5: Add this markup to a page.

Warning: Your TagHelper class, if its name has CaSe, must be referenced in lowercase with a ‘-‘ separating the words. For example, EmailSupport becomes <email-support>.

<email-support></email-support>

 


The result:

taghelperemail.png

Beautiful button, beautiful markup

ASP.NET Core 2: Using SQLite as a light weight database

SQLite370.svg.pngAzure is a great place to store your data of any size, but sometimes that may not be possible for a number of reasons. In this article I’ll show you how to use Microsoft Entity Framework Core (EF) and SQLite to create and store a small amount of data.

This code is a bare-bones example. It doesn’t include important features like error handling or DI.

Note: There is no database file. EF Core will create the SQLite database file for you.

Step 1: Create any simple ASP.NET Core site via the (File | New) menu

Step 2: Add these NuGet packages

  1. Microsoft.EntityFrameworkCore
  2. Microsoft.EntityFrameworkCore.Sqlite
  3. Microsoft.EntityFrameworkCore.Sqlite.Core

Step 3: DbContext

All of the magic takes place in a single simple data class. Add this to your solution:

public class SimpleDataStorageDbContext
{
    public SimpleDataStorage(){}
 
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        //Set the filename of the database to be created
        optionsBuilder.UseSqlite("Data Source=db.sqlite");
    }
 
    public DbSet<Cat> Cats { getset; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
 
        //Define the Table(s) and References to be created automatically
        modelBuilder.Entity<Cat>(b =>
        {
            b.HasKey(e => e.Id);
            b.Property(e => e.Id).ValueGeneratedOnAdd();
            b.Property(e => e.Name).IsRequired().HasMaxLength(255);
            b.ToTable("Cats");
        });
    }
}

What’s very interesting here is that the database doesn’t exist, the class SimpleDataStorage tells EF how and where to create it.

Step 4: Create the database and tables in Startup.cs

public class Startup
{
   public Startup()
    {
        using (var client = new SimpleDataStorage())
        {
            //Create the database file at a path defined in SimpleDataStorage
            client.Database.EnsureCreated();
            //Create the database tables defined in SimpleDataStorage
            client.Database.Migrate();
        }
    }

Step 5: Add Cats to the database!

We can now access the database anywhere in code

public IActionResult Index(SimpleDataStorage db)
{
    for (int i = 0; i < 1000; i++)
    {
        db.Cats.Add(new Cat() {Name = "Caty McCat: " + i}); 
    }
    db.SaveChanges(true);
    return View();
}


Resources: A good SQLite database editor

 

ASP.NET Core 2: Injecting Services into Razor pages

cat2.pngInject all the things.

Injecting dependencies into Razor pages is a new feature in ASP.NET Core designed to help with testing and simplicity.

Are cat pictures funny? The article will help answer that age-old question using a service injected into a Razor page.

Step 1: Create a service and interface

public class FunnyCatManagerIFunnyCat
{
    public string AreCatsFunny => "Yes";
}
 
public interface IFunnyCat
{
    string AreCatsFunny { get;}
}

Step 2: Add the IFunnyCat interface to ASP.NET Core’s dependency injection. Edit the Startup.cs file and add this:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
         services.AddTransient(typeof(IFunnyCat), typeof(FunnyCatManager));

Step 3: Inject the IFunnyCat implementation into a Razor page

@inject IFunnyCat CatManager
Are Cats Funny? <b>@CatManager.AreCatsFunny</b>

The result looks like this:

cat.png

Cats are indeed funny

ASP.NET Core 2: Custom Authentication Part 2

Browser-Cookies.jpgIn Part 1 we asked ASP.NET Core to use Cookie based authentication and to include the authentication engine into the request pipeline. In this next simple example, we’ll log the user in and verify they are logged in. ASP.NET Core has a built-in user system, however in these posts I’m assuming you can’t use that and have to use an external user database or web service.

To keep this as narrowly focused as possible, I am skipping the User Manager features like looking up the user in a database and comparing password hashes. If you need a good UserManager.cs file for ASP.NET Core outside of the built-in one, here’s a good one.

In the HomeController.cs add this function. It’ll handle a complete Login:

[AllowAnonymous]
public async Task<IActionResult> SignIn()
{
 
    //Create a plain C# Class
    //In real-life, get this from a database after verifying the username and password
    MyUser user = new MyUser()
    {
        Id = 1,
        Name = "Fred Fish"
    };
 
    //Add the ID of the user and the name to a collection of Claims
    List<Claim> claims = new List<Claim>
    {
        new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
        new Claim(ClaimTypes.Name, user.Name)
    };
 
    //Create the principal user from the claims
    ClaimsIdentity identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    ClaimsPrincipal principal = new ClaimsPrincipal(identity);
    AuthenticationProperties authenticationProperties = new AuthenticationProperties() {IsPersistent = false};
 
    //Ask MVC to create the auth cookie and store it
    await this.HttpContext
            .SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, 
             principal, authenticationProperties);
 
 
    //DONE!
    return this.RedirectToAction("Index");
}

Let’s break this down now:

We first need a User class, this can be a plain old C# object. There is no magic here.

public class MyUser
{
    public int Id { getset; }
    public string Name { getset; }
}

Next we need to add information about the user we just made to a collection of Claims. Claims can contain groups or roles or names and ids. Think of it as the bucket of certified security information about a user.

List<Claim> claims = new List<Claim>
{
    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
    new Claim(ClaimTypes.Name, user.Name)
};

We now wrap up all the claims and info about the user into a Principal:

ClaimsIdentity identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
AuthenticationProperties authenticationProperties = new AuthenticationProperties() { IsPersistent = false };
ClaimsPrincipal principal = new ClaimsPrincipal(identity);

And finally, take the Principal and ask the HttpContext to store it in a cookie:

await this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, authenticationProperties);

We are now logged in. To check, in the post-login View, have a look at the User

@if (this.User.Identity.IsAuthenticated)
{
    <b>Authenticated!</b>
} 

Done!

 

ASP.NET Core 2: Custom Authentication Part 1

ASP.NET Core 2 comes with easy to use out-of-the-box authentication. In Visual Studio 2017 you can create fully functioning projects via the File | New menu.

These next few tutorials will focus on doing a custom implementation. Perhaps your organization wishes to authenticate against a customer database, or even a web service. I’ll show you how to implement that all using the beautiful ASP.NET Core 2 authentication infrastructure.

Step 1: Create a new blank project, no authentication

For this tutorial we’ll use “.NET Framework” as we’ll be hosting in IIS

custom auth.png

Step 2: Add the NuGet package Microsoft.AspNetCore.Authentication.Cookies

Step 3: In Startup.cs add Cookie customization for the authentication cookie:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
            {
                options.ExpireTimeSpan = TimeSpan.FromDays(7);
                options.LoginPath = "/Account/CustomLogin";
                options.Cookie.Name = "MyAuthCookieName";
            }
        );
 
    services.AddMvc();
}

Step 4: In Startup.cs ‘s Configure method add UseAuthentication()

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseBrowserLink();
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }
 
    app.UseAuthentication();  //IMPORTANT
    app.UseStaticFiles();

 

 

In the cookie customization, you can change many features like the login page from the default “/Account/Login” and the name of the Cookie. The defaults are sensible however.

In Part 2 we’ll add a UserManager class which will handle authentication.

This post is possible based on the excellent work at this site.

ASP.NET Core 2: Adding an Authorization Policy

In ASP.NET Core, an Authorization Policy is simply some code that says “Are you allowed to do something” In this rather contrived example, we’re going to only allow access to a Controller’s Action if a weather service indicates it’s raining. Why not 🙂

Step 1: Create a new solution that has some kind of authentication. Doesn’t matter what kind.

Authentication aspnet core.png

Step 2: Create a new AuthorizationPolicyBuilder extension class so we can add the Policy in our Startup.cs in step 3 next.

public static class WeatherAuthorizationPolicy
{
    public static string Name => "IsRaining";
    public static void Build(AuthorizationPolicyBuilder builder)
    {
        builder.RequireAssertion(context => IsRaining(context.User));
    }
    public static bool IsRaining(ClaimsPrincipal user)
    {
        //Todo access a weather service here.
        //return GetWeatherForUser(user);
        return true;
    }
 }

Step 3: Add the Policy in your Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options.AddPolicy(WeatherAuthorizationPolicy.Name, 
                      WeatherAuthorizationPolicy.Build);
    });

Step 4: Add an Authorize attribute to an Action

[Authorize("IsRaining")]
public IActionResult RainInSpain()
{ 
    return View();
}

That’s it.


BONUS

I would recommend creating a Authorize Attribute so that you don’t have the magic string “IsRaining” all over the place. Excluded for simplicity.

public class AuthorizeIsRaining : AuthorizeAttribute
{
    public AuthorizeIsRaining()
           :base(WeatherAuthorizationPolicy.Name) {}
}

You can also call this policy in code by using an injected IAuthorizationService:

public MyNiceController(IAuthorizationService  authorizationService)
{
    _authorizationService = authorizationService;
}
public async Task CheckRain()
{
    var result = await _authorizationService
                .AuthorizeAsync(User, WeatherAuthorizationPolicy.Name);
     if (result.Succeeded)
        { .... }
}