Quantcast
Channel: All About ASP.NET and ASP.NET Core 2 Hosting BLOG
Viewing all 427 articles
Browse latest View live

ASP.NET Core Hosting - Understanding File uploads in ASP.NET Core

$
0
0

Uploading file or image in ASP.NET Core is very easy. ASP.NET MVC actions support uploading of one or more files using simple model binding for smaller files or streaming for larger files. In this article we will learn how to upload any file in ASP.NET Core. We will see how can we use different features of ASP.NET Core to upload small file as well as any large file.

Uploading small files with model binding

To upload small files, you can use a multi-part HTML form or construct a POST request using JavaScript. An example form using Razor, which supports multiple uploaded files, is shown below:

<form method="post" enctype="multipart/form-data" asp-controller="UploadFiles" asp-action="Index">
    <div class="form-group">
        <div class="col-md-10">
            <p>Upload one or more files using this form:</p>
            <input type="file" name="files" multiple="">
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-10">
            <input type="submit" value="Upload">
        </div>
    </div>
</form>

In order to support file uploads, HTML forms must specify an enctype of multipart/form-data. The files input element shown above supports uploading multiple files. Omit the multiple attribute on this input element to allow just a single file to be uploaded. The above markup renders in a browser as:

Uploading small files with model binding

The individual files uploaded to the server can be accessed through Model Binding using the IFormFile interface. IFormFile has the following structure:

public interface IFormFile
{
    string ContentType { get; }
    string ContentDisposition { get; }
    IHeaderDictionary Headers { get; }
    long Length { get; }
    string Name { get; }
    string FileName { get; }
    Stream OpenReadStream();
    void CopyTo(Stream target);
    Task CopyToAsync(Stream target, CancellationToken cancellationToken = null);
}

Warning:- Don't rely on or trust the FileName property without validation. The FileName property should only be used for display purposes.

When uploading files using model binding and the IFormFile interface, the action method can accept either a single IFormFile or an IEnumerable<IFormFile> (or List<IFormFile>) representing several files. The following example loops through one or more uploaded files, saves them to the local file system, and returns the total number and size of files uploaded.

Warning:- The following code uses GetTempFileName, which throws an IOException if more than 65535 files are created without deleting previous temporary files. A real app should either delete temporary files or use GetTempPath and GetRandomFileName to create temporary file names. The 65535 files limit is per server, so another app on the server can use up all 65535 files.

[HttpPost("UploadFiles")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
    long size = files.Sum(f => f.Length);
 
    // full path to file in temp location
    var filePath = Path.GetTempFileName();
 
    foreach (var formFile in files)
    {
        if (formFile.Length > 0)
        {
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await formFile.CopyToAsync(stream);
            }
        }
    }
 
    // process uploaded files
    // Don't rely on or trust the FileName property without validation.
 
    return Ok(new { count = files.Count, size, filePath});
}

Files uploaded using the IFormFile technique are buffered in memory or on disk on the web server before being processed. Inside the action method, the IFormFile contents are accessible as a stream. In addition to the local file system, files can be streamed to Azure Blob storage or Entity Framework.

To store binary file data in a database using Entity Framework, define a property of type byte[] on the entity:

public class ApplicationUser : IdentityUser
{
    public byte[] AvatarImage { get; set; }
}
Specify a viewmodel property of type IFormFile:
public class RegisterViewModel
{
    // other properties omitted
 
    public IFormFile AvatarImage { get; set; }
}

Note:- IFormFile can be used directly as an action method parameter or as a viewmodel property, as shown above.

Copy the IFormFile to a stream and save it to the byte array:

// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
    ViewData["ReturnUrl"] = returnUrl;
    if  (ModelState.IsValid)
    {
        var user = new ApplicationUser {
          UserName = model.Email,
          Email = model.Email
        };
        using (var memoryStream = new MemoryStream())
        {
            await model.AvatarImage.CopyToAsync(memoryStream);
            user.AvatarImage = memoryStream.ToArray();
        }
    // additional logic omitted
 
    // Don't rely on or trust the model.AvatarImage.FileName property
    // without validation.
}

Note:- Use caution when storing binary data in relational databases, as it can adversely impact performance.

Uploading large files with streaming

If the size or frequency of file uploads is causing resource problems for the app, consider streaming the file upload rather than buffering it in its entirety, as the model binding approach shown above does. While using IFormFile and model binding is a much simpler solution, streaming requires a number of steps to implement properly.

Note:- Any single buffered file exceeding 64KB will be moved from RAM to a temp file on disk on the server. The resources (disk, RAM) used by file uploads depend on the number and size of concurrent file uploads. Streaming is not so much about perf, it's about scale. If you try to buffer too many uploads, your site will crash when it runs out of memory or disk space.

The following example demonstrates using JavaScript/Angular to stream to a controller action. The file's antiforgery token is generated using a custom filter attribute and passed in HTTP headers instead of in the request body. Because the action method processes the uploaded data directly, model binding is disabled by another filter. Within the action, the form's contents are read using a MultipartReader, which reads each individual MultipartSection, processing the file or storing the contents as appropriate. Once all sections have been read, the action performs its own model binding.

The initial action loads the form and saves an antiforgery token in a cookie (via the GenerateAntiforgeryTokenCookieForAjax attribute):

[HttpGet]
[GenerateAntiforgeryTokenCookieForAjax]
public IActionResult Index()
{
    return View();
}

The attribute uses ASP.NET Core's built-in Antiforgery support to set a cookie with a request token:

public class GenerateAntiforgeryTokenCookieForAjaxAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        var antiforgery = context.HttpContext.RequestServices.GetService<IAntiforgery>();
 
        // We can send the request token as a JavaScript-readable cookie,
        // and Angular will use it by default.
        var tokens = antiforgery.GetAndStoreTokens(context.HttpContext);
        context.HttpContext.Response.Cookies.Append(
            "XSRF-TOKEN",
            tokens.RequestToken,
            new CookieOptions() { HttpOnly = false });
    }
}

Angular automatically passes an antiforgery token in a request header named X-XSRF-TOKEN. The ASP.NET Core MVC app is configured to refer to this header in its configuration in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // Angular's default header name for sending the XSRF token.
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
 
    services.AddMvc();
}

The DisableFormValueModelBinding attribute, shown below, is used to disable model binding for the Upload action method.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var formValueProviderFactory = context.ValueProviderFactories
            .OfType<FormValueProviderFactory>()
            .FirstOrDefault();
        if (formValueProviderFactory != null)
        {
            context.ValueProviderFactories.Remove(formValueProviderFactory);
        }
 
        var jqueryFormValueProviderFactory = context.ValueProviderFactories
            .OfType<JQueryFormValueProviderFactory>()
            .FirstOrDefault();
        if (jqueryFormValueProviderFactory != null)
        {
            context.ValueProviderFactories.Remove(jqueryFormValueProviderFactory);
        }
    }
 
    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

Since model binding is disabled, the Upload action method doesn't accept parameters. It works directly with the Request property of ControllerBase. A MultipartReader is used to read each section. The file is saved with a GUID filename and the key/value data is stored in a KeyValueAccumulator. Once all sections have been read, the contents of the KeyValueAccumulator are used to bind the form data to a model type.

The complete Upload method is shown below:

Warning:- The following code uses GetTempFileName, which throws an IOException if more than 65535 files are created without deleting previous temporary files. A real app should either delete temporary files or use GetTempPath and GetRandomFileName to create temporary file names. The 65535 files limit is per server, so another app on the server can use up all 65535 files.

// 1. Disable the form value model binding here to take control of handling
//    potentially large files.
// 2. Typically antiforgery tokens are sent in request body, but since we
//    do not want to read the request body early, the tokens are made to be
//    sent via headers. The antiforgery token filter first looks for tokens
//    in the request header and then falls back to reading the body.
[HttpPost]
[DisableFormValueModelBinding]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Upload()
{
    if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
    {
        return BadRequest($"Expected a multipart request, but got {Request.ContentType}");
    }
 
    // Used to accumulate all the form url encoded key value pairs in the
    // request.
    var formAccumulator = new KeyValueAccumulator();
    string targetFilePath = null;
 
    var boundary = MultipartRequestHelper.GetBoundary(
        MediaTypeHeaderValue.Parse(Request.ContentType),
        _defaultFormOptions.MultipartBoundaryLengthLimit);
    var reader = new MultipartReader(boundary, HttpContext.Request.Body);
 
    var section = await reader.ReadNextSectionAsync();
    while (section != null)
    {
        ContentDispositionHeaderValue contentDisposition;
        var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
 
        if (hasContentDispositionHeader)
        {
            if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
            {
                targetFilePath = Path.GetTempFileName();
                using (var targetStream = System.IO.File.Create(targetFilePath))
                {
                    await section.Body.CopyToAsync(targetStream);
 
                    _logger.LogInformation($"Copied the uploaded file '{targetFilePath}'");
                }
            }
            else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
            {
                // Content-Disposition: form-data; name="key"
                //
                // value
 
                // Do not limit the key name length here because the
                // multipart headers length limit is already in effect.
                var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name);
                var encoding = GetEncoding(section);
                using (var streamReader = new StreamReader(
                    section.Body,
                    encoding,
                    detectEncodingFromByteOrderMarks: true,
                    bufferSize: 1024,
                    leaveOpen: true))
                {
                    // The value length limit is enforced by MultipartBodyLengthLimit
                    var value = await streamReader.ReadToEndAsync();
                    if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase))
                    {
                        value = String.Empty;
                    }
                    formAccumulator.Append(key, value);
 
                    if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit)
                    {
                        throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded.");
                    }
                }
            }
        }
 
        // Drains any remaining section body that has not been consumed and
        // reads the headers for the next section.
        section = await reader.ReadNextSectionAsync();
    }
 
    // Bind form data to a model
    var user = new User();
    var formValueProvider = new FormValueProvider(
        BindingSource.Form,
        new FormCollection(formAccumulator.GetResults()),
        CultureInfo.CurrentCulture);
 
    var bindingSuccessful = await TryUpdateModelAsync(user, prefix: "",
        valueProvider: formValueProvider);
    if (!bindingSuccessful)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
    }
 
    var uploadedData = new UploadedData()
    {
        Name = user.Name,
        Age = user.Age,
        Zipcode = user.Zipcode,
        FilePath = targetFilePath
    };
    return Json(uploadedData);
}

Troubleshooting

Below are some common problems encountered when working with uploading files and their possible solutions.

Unexpected Not Found error with IIS

The following error indicates your file upload exceeds the server's configured maxAllowedContentLength:

HTTP 404.13 - Not Found

The request filtering module is configured to deny a request that exceeds the request content length.
The default setting is 30000000, which is approximately 28.6MB. The value can be customized by editing web.config:

<system.webserver>
  <security>
    <requestfiltering>
      <!-- This will handle requests up to 50MB -->
      <requestlimits maxallowedcontentlength="52428800"></requestlimits>
    </requestfiltering>
  </security>
</system.webserver>

Null Reference Exception with IFormFile

If your controller is accepting uploaded files using IFormFile but you find that the value is always null, confirm that your HTML form is specifying an enctype value of multipart/form-data. If this attribute is not set on the <form> element, the file upload will not occur and any bound IFormFile arguments will be null.

Best ASP.NET Core Hosting Recommendation

ASPHostPortal.comprovides its customers with Plesk Panel, one of the most popular and stable control panels for Windows hosting, as free. You could also see the latest .NET framework, a crazy amount of functionality as well as Large disk space, bandwidth, MSSQL databases and more. All those give people the convenience to build up a powerful site in Windows server. ASPHostPortal.com offers ASP.NET hosting starts from $1/month only. They also guarantees 30 days money back and guarantee 99.9% uptime. If you need a reliable affordable ASP.NET Hosting, ASPHostPortal.com should be your best choice.


ASP.NET Core 2 Hosting :: How to Create Simple Shoutbox Using ASP.NET Core Razor Pages

$
0
0

ASP.NET Core 2 comes with Razor Pages that allow developers to build simple web applications with less overhead compared to MVC. The emphasis is on the word “simple” as Razor Pages doesn’t come with patterns suitable for bigger and more complex applications. For this, we have MVC that is flexible enough to build applications that will grow over years. This blog post uses a simple shoutbox application to illustrate how to build applications using Razor Pages.

Shoutbox Application

This post introduces how to build a simple and primitive shoutbox application using ASP.NET Core and Razor Pages. We will also use SQL Server LocalDb and Entity Framework Core code-first to make things more interesting. The goal of this post is to demonstrate how to use Razor Pages pages with and with-out a backing model.

We will build a fully functional application you can use to further dig around and discover the secrets of Razor Pages.

Creating a Razor Pages Application

Let’s start with a new ASP.NET Core Razor Pages project. Yes, now there is a new template for this. 

 

Razor Pages projects have a similar structure to MVC ones, but, as there are some differences, like Pages folder, and as Razor Pages doesn’t have controllers, we don’t have a controllers folder. Also, there’s no folder for views.

Database, Data Context, and Shoutbox Entity

We will use SQL Server LocalDB as our database and we will go with Entity Framework Core code-first. The first thing to do is to modify appsettings.json and add a connection string: I leave everything else like it is.

{
  "ConnectionStrings": {
    "ShoutBoxContext": "Server=(localdb)\\mssqllocaldb;Database=ShoutBoxContext;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  }

Let’s also create a simple entity class for our shoutbox item. As we don’t create model mappings we have to use data annotations to let the data context know how to create a database table.

public class ShoutBoxItem
{
    [Key]
    public int Id { get; set; }
    [Required]
    public DateTime? Time { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string Message { get; set; }
}

To communicate with the database we need a database context class too. We keep our database context as minimal as reasonably possible.

public class ShoutBoxContext : DbContext
{
    public ShoutBoxContext(DbContextOptions<ShoutBoxContext> options) : base(options)
    { }
    public DbSet<ShoutBoxItem> ShoutBoxItems { get; set; }
}

Finally, we need to introduce our database context to a framework-level dependency injection mechanism. We can do this with the ConfigureServices()method of the Startup class.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddDbContext<ShoutBoxContext>(options => {n
        options.UseSqlServer(Configuration.GetConnectionString("ShoutBoxContext"));
    });
    services.AddTransient<ShoutBoxContext>();
}

Before using the database, we must ensure it is there and available. For this, we add an EnsureCreated()call to the ends of the Configure() method of the Startup class.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }
    app.UseStaticFiles();
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
    app.ApplicationServices.GetRequiredService<ShoutBoxContext>()
                           .Database
                           .EnsureCreated();
}

Now we have everything we need to start building the user interface for our simple shoutbox application.

Building Shout List

Our simple application will show the 100 latest shouts as a list on the front page. This view is an example of a page with no code-behind file. All the work is done on the page itself. We will use it to get our data context to the page.

@page
@inject RazorPagesShoutBox.Data.ShoutBoxContext dataContext
@{
    ViewData["Title"] = "Home Page";
    var shouts = dataContext.ShoutBoxItems
                            .OrderByDescending(s => s.Time)
                            .Take(100)
                            .ToList();
}
<h2>@ViewData["Title"]</h2>
<div class="row">
    <div class="col-md-10">
        @if (shouts.Any())
        {
            foreach (var shout in shouts)
            {
                <p>
                    <strong>@shout.Name</strong> | @shout.Time.ToString()<br />
                    @Html.Raw(shout.Message.Replace("\r\n", "<br />"))
                </p>
            }
        }
        else
        {
            <p>No shouts... be the firts one!</p>
        }
    </div>
</div>
<a href="AddShout">Add shout</a>

At the end of the page, we have a link to the page where the user can add a new shout.

Building New Shout Form

To let users shout, we create a separate page and this time we will use code-behind file where the model for the page is defined. Notice the @model directive in the page code.

@page
@model AddShoutModel
@{
    ViewData["Title"] = "Add shout";
}
<h2>@ViewData["Title"]</h2>
<div class="row">
    <div class="col-md-10">
        <form method="post">
            <div class="form-group">
                <label asp-for="Item.Name"></label>
                <input class="form-control" asp-for="Item.Name" />
                @Html.ValidationMessageFor(m => m.Item.Name)
            </div>
            <div class="form-group">
                <label asp-for="Item.Message"></label>
                <textarea class="form-control" asp-for="Item.Message"></textarea>
                @Html.ValidationMessageFor(m => m.Item.Message)
            </div>
            <input type="hidden" asp-for="Item.Time" />
            <button type="submit" class="btn-default">Shout it!</button>
        </form>
    </div>
</div>

All models that support pages are inherited from the PageModel class. We use constructor injection to get our data context to the page model. The model we want to show on the page is represented by Item property. The BindProperty attribute tells ASP.NET Core that data from the form must be bound to this property. Without it, we must write code to extract values from the request and do all the dirty work by ourselves. The OnGet() method of the page model is called when the page is loaded using the HTTP GET method and OnPost() is called when a POST was made.

public class AddShoutModel : PageModel
{
    private readonly ShoutBoxContext _context;
    public AddShoutModel(ShoutBoxContext context)
    {
        _context = context;
    }
    [BindProperty]
    public ShoutBoxItem Item { get; set; }
    public void OnGet()
    {
        if (Item == null)
        {
            Item = new ShoutBoxItem();
        }
        Item.Time = DateTime.Now;
    }
    public IActionResult OnPost()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
        Item.Id = 0;
        _context.ShoutBoxItems.Add(Item);
        _context.SaveChanges();
        return RedirectToPage("Index");
    }
}

It’s time to run the application and make some serious shouts!

Wrapping Up

Razor Pages provides us with a thinner model to build applications and it’s suitable for small applications. As it is part of ASP.NET Core MVC, it supports many features that come with MVC. The PageModel is like a mix of models and controllers in MVC and its purpose is to provide the separation of presentation and logic. We can use Razor Pages to build pages with or without a backing model and it is completely up to us to decide which way to go. 

ASP.NET Core 2 Hosting :: How to Fix Error 502.5 When Deploy Your ASP.NET Core

$
0
0

I decide to make this tutorial as most of our users also experience same problem when deploying their ASP.NET Core application.

I recently hit this problem after manually modifying the web.config file. Fortunately, the problem is easy to fix.

In this post, we see two different causes of this error, two different solutions for the first cause, a solution for the second cause, and learn what needs to be in web.config for ASP.NET Core to operate.

The Error

Here is a screenshot of the HTTP Error 502.5 - Process Failure error. You'll see this, in your browser, when making a request to your ASP.NET Core application, after deployment, if you have this issue.

Why do I get the error?

The HTTP Error 502.5 - Bad Gateway and HTTP Error 502.5 - Process Failure error messages occur in ASP.NET Core when IIS fails to execute the dotnet process.

I've seen this error happen for two different reasons:

  • .NET Core Runtime is not installed
  • web.config file has not been transformed

How to Fix This Error?

This is very simple and easy to fix this issue. What you need to make sure is that your hosting provider support or already installed the latest ASP.NET Core on their hosting environment.

1. Install Latest .NET Core Runtime

You can download the latest .NET Core runtime from Microsoft's .NET download page.

For Windows, you'll usually want the latest .NET Core runtime (currently v2.1.1), as highlighted in the following screenshot:

This will get you the Windows Hosting Bundle Installer, which will install both the x86 and x64 runtimes on Windows Server.

2. Publish a Self-Contained Deployment

If you don't want to install the .NET Core Runtime. An alternative for .NET Core web applications is to publish them in the Self-Containeddeployment mode, which includes the required .NET Runtime files alongside your application.

You can select this option from the advanced publish settings screen in Visual Studio: 

If you go with this option, you'll also need to choose a target runtime: win-x86, win-x64, osx-x64, or linux-x64. Because self-contained deployments are not portable.

3. Transform your web.config file

Another reason for this error to occur is when you deploy an untransformed web.config file. This is likely to be your issue if you had a previously working web application and merely deployed a new version of it.

ASP.NET Core Web Config

In ASP.NET Core applications, the web.config file contains a handler that directs requests to the AspNetCoreModule and an aspNetCoreelement that defines and configures the ASP.NET Core process to execute your web application.

Here is a minimal web.config file for an ASP.NET Core application:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 
<system.webServer>
   
<handlers>
     
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
   
</handlers>
   
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="true"
       
stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
 
</system.webServer>
</configuration>

Note that it's possible that you don't have a web.config file in your ASP.NET Core project. If you do not, one will be generated for you when publishing the project, as IIS and IIS Express require a web.config file when hosting an ASP.NET Core web app.

The Issue

The untransformed web.config contains the variables %LAUNCHER_PATH% and %LAUNCHER_ARGS% rather than the correct paths. When IIS tries to run ASP.NET Core, it uses %LAUNCHER_PATH% and %LAUNCHER_ARGS% rather than the correct path and arguments.

To fix the HTTP Error 502.5 in ASP.NET Core, you need to transform the web.config and replace the untransformed web.config file on the IIS web server.

How do I transform web.config?

This transformation takes place when you choose to publish your web application. The transformed web.config ends up in the published output folder. Therefore, you simply need to publish your web application and copy the resulting web.config file onto the server.

In a transformed web.config file, the aspNetCore element will look something like this:

<aspNetCore processPath="dotnet" arguments=".\MyApplication.dll" stdoutLogEnabled="true"
    stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" />

%LAUNCHER_PATH% has been replaced by dotnet and %LAUNCHER_ARGS% has been replaced by the path to the main web application dll .\MyApplication.dll.

ASP.NET Core Hosting :: How to Fix Error "An error occurred while starting the application" in ASP.NET Core

$
0
0

Previously, we have written tutorial about how to fix 502.5 error that you face when publishing your ASP.NET Core application. Another issue that you might face when publishing your .net Core application is:

“An error occurred while starting the application.  .NET Framework <version number> | Microsoft.AspNetCore.Hosting version <version number> | Microsoft Windows <version number>”

It looks like:

What happened?

It basically means something really bad happened with your app.  Some things that might have gone wrong:

  • You might not have the correct .NET Core version installed on the server.
  • You might be missing DLL’s
  • Something went wrong in your Program.cs or Startup.cs before any exception handling kicked in

Event Viewer (Probably) Won’t Show You Anything

If you’re running on Windows and behind IIS, you might immediately go to the Event Viewer to see what happened based on your previous ASP.NET knowledge.  You’ll notice that the error is not there.  This is because Event Logging must be wired up explicitly and you’ll need to use the Microsoft.Extensions.Logging.EventLog package, and depending on the error, you might not have a chance to even catch it to log to the Event Viewer.

How to figure out what happened (if running on IIS)

Instead of the Event Viewer, if you’re running behind IIS, we can log the request out to a file.  To do that:

  1. Open your web.config
  2. Change stdoutLogEnabled=true
  3. Create a logs folder
    - Unfortunately, the AspNetCoreModule doesn’t create the folder for you by default. If you forget to create the logs folder, an error will be logged to the Event Viewer that says: Warning: Could not create stdoutLogFile \\?\YourPath\logs\stdout_timestamp.log, ErrorCode = -2147024893.
    -
    The “stdout” part of  the value “.\logs\stdout” actually references the filename not the folder.  Which is a bit confusing.
  4. Run your request again, then open the \logs\stdout_*.log file

Note – you will want to turn this off after you’re done troubleshooting, as it is a performance hit.

So your web.config’s aspNetCore element should look something like this

 <aspNetCore processPath=”.\YourProjectName.exe” stdoutLogEnabled=”true” stdoutLogFile=”.\logs\stdout” />

Doing this will log all the requests out to this file and when the exception occurs, it will give you the full stack trace of what happened in the \logs\stdout_*.log file

 

Hope this helps. In case, you need ASP.NET Core hosting, you can always try our services start from $1.00/month.

ASP.NET Hosting :: How to Setup URL Redirection

$
0
0

We have so many clients asking about this issue. So, we decide to write this tutorial and hope this information can help other people too. In this review, we will write simple tutorial about how to setup http/https redirection in IIS.

There are lots of routing options accessible in ASP.NET but still it comes a time when you need to manipulate a URL and manipulating it outside a code comes handy. When this happens, the best you can do id to use IIS Rewrite Module. Transforming various URL’s out of code enables you to do various things including performing redirections for archive or transferred content without interfering with the code, you can easily implement SEO optimizations and tweaks quickly and easily without code and many more. Below is a collection of useful IIS rewrite rules that will help you understand IIS rewrites.

Useful IIS Rewrite Rules

Adding www Prefix

This is a basic rule that adds prefix “www” to any URL you need. This is a requirement for SEO.

Redirection from Domain 1 to Domain 2

This rule comes handy when you change the name of your site or may be when you need to catch and alias and direct it to your main site. If the new and the old URLs share some elements, then you could just use this rule to have the matching pattern together with the redirect target being.

HTTPS/HTTP Redirection

Redirecting users from HTTP to HTTPS is one of the reasons that you need to apply useful IIS rewrite rules. It can lead to conditional statements while looking for dev/test mode in your code. This rules allows you to handle the redirection without much statements which is tidier.

There is a pair of rules in this case each for one of the two ways. In both the rules, a check is performed to verify that the protocol used is http/https. The rules work on the same URL patterns or the similar lists of pages to match. For the redirect to HTTP, it is not about matching the pages; it is a reverse of the first rule and usually have a number of .NET/site paths that are excluded.

Setup Redirection Using IIS

Above steps is to setup URL redirection via your code. But, if you manage your own server, you can also setup redirection via IIS. The following is the steps

1. Download and install the “URL Rewrite” module.

2. Open the “IIS Manager” console and select the website you would like to apply the redirection to in the left-side menu:



3. Double-click on the “URL Rewrite” icon.

4. Click “Add Rule(s)” in the right-side menu.

5. Select “Blank Rule” in the “Inbound” section, then press “OK”:

6. Enter any rule name you wish.

7. In the “Match URL” section:

- Select “Matches the Pattern” in the “Requested URL” drop-down menu 
- Select “Regular Expressions” in the “Using” drop-down menu 
- Enter the following pattern in the “Match URL” section: “(.*)” 
- Check the “Ignore case” box

 

 

8. In the “Conditions” section, select “Match all” under the “Logical Grouping” drop-down menu and press “Add”.

9. In the prompted window:

- Enter “{HTTPS}” as a condition input 
- Select “Matches the Pattern” from the drop-down menu 
- Enter “^OFF$” as a pattern 
- Press “OK”

10. In the “Action” section, select “Redirect” as the action type and specify the following for “Redirect URL”:

https://{HTTP_HOST}/{R:1}

11. Check the “Append query string” box.

12.Select the Redirection Type of your choice. The whole “Action” section should look like this:

 

NOTE: There are 4 redirect types of the redirect rule that can be selected in that menu: 

- Permanent (301) – preferable type in this case, which tells clients that the content of the site is permanently moved to the HTTPS version. Good for SEO, as it brings all the traffic to your HTTPS website making a positive effect on its ranking in search engines. 
- Found (302) – should be used only if you moved the content of certain pages to a new place *temporarily*. This way the SEO traffic goes in favour of the previous content’s location. This option is generally not recommended for a HTTP/HTTPS redirect. 
- See Other (303) – specific redirect type for GET requests. Not recommended for HTTP/HTTPS. 
- Temporary (307) – HTTP/1.1 successor of 302 redirect type. Not recommended for HTTP/HTTPS.

13. Click on “Apply” on the right side of the “Actions” menu.

The redirect can be checked by accessing your site via http:// specified in the URL. To make sure that your browser displays not the cached version of your site, you can use anonymous mode of the browser.

The rule is created in IIS, but the site is still not redirected to https://

Normally, the redirection rule gets written into the web.config file located in the document root directory of your website. If the redirection does not work for some reason, make sure that web.config exists and check if it contains the appropriate rule.

To do this, follow these steps:

1. In the sites list of IIS, right-click on your site. Choose the “Explore” option:

 

2. “Explore” will open the document root directory of the site. Check if the web.config file is there.

3. The web.config file must have the following code block:

<configuration> 
<system.webServer> 
<rewrite> 
<rules> 
<rule name="HTTPS force" enabled="true" stopProcessing="true"> 
<match url="(.*)" /> 
<conditions> 
<add input="{HTTPS}" pattern="^OFF$" /> 
</conditions> 
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" /> 
</rule> 
</rules> 
</rewrite> 
</system.webServer> 
</configuration>

4. If the web.config file is missing, you can create a new .txt file, put the aforementioned code there, save and then rename the file to web.config.

 

 

ASP.NET Core Hosting :: Differences Between Kestrel and IIS Features

$
0
0

The Kestrel web server is a new web server as part of ASP.NET Core. It is now the preferred web server for all new ASP.NET applications. In this article, we will review what it is, how to use it, and the differences between Kestrel vs IIS.

Why Do We Need the New Kestrel Web Server? What about IIS?

If you have been developing ASP.NET applications for a while, you are probably familiar with Internet Information Services (IIS). It does literally anything and everything as a web server. It is infinitely configurable with ASP.NET handlers & modules via the ASP.NET integrated pipeline. It has robust management APIs for configuration and deployment. It is even an FTP server.

The same codebase that has to support the original “.asp” pages from 15+ years ago now also handles new technologies like async ASP.NET. Like most software, as it ages it gets modified over time, they carry a lot of weight and bloat. IIS does everything, but it is not the fastest web server around. Lightweight web servers like Node.js and Netty make IIS look old and slow.

A Chance to Start Over

By creating the Kestrel web server, the .NET community was able to start over from scratch. They no longer had to worry about backward compatibility for technologies that were 15+ years old. They could take all of their past knowledge to build the simplest and fastest web server possible. That is exactly what they did. Kestrel and ASP.NET Core were built for speed.

Kestrel is more than just a new web server. ASP.NET Core & Kestrel combined are a whole new request pipeline for how ASP.NET requests work. Things like HTTP modules & handlers have been replaced with simple middleware. The entire System.Web namespace is gone. Another big advantage is designing a web server to take advantage of async from the ground up. Performance is now a feature of ASP.NET.

Built for Speed

One of the big problems with IIS and the existing ASP.NET pipeline was the performance of it. For most real world applications, the performance is perfectly fine. However, it lagged way behind in benchmarks. The combination of Kestrel & ASP.NET Core has been shown to be many times faster. It is great to see the team putting performance as a top priority.

Granted, benchmarking an ASP.NET request that says “hello world” is not comparable to most real applications that do multiple SQL queries, cache calls, and web service calls in a single request. ASP.NET makes it easy to do most I/O operations asynchronously. ASP.NET Core & Kestrel have been designed from the ground up to take advantage of async. Most real world apps should perform better if the developers follow good best practices around using async.

Cross Platform

If the goal was to get ASP.NET running on Linux, that meant porting IIS to Linux or making ASP.NET work without IIS. Kestrel solved this problem. As a developer, I can write my ASP.NET application and deploy it to Windows or Linux either one. Kestrel works as my web server on both. However, it is still recommended to use IIS, Apache, or NGINX as a reverse proxy in front of it. Next, we will discuss why that is.

Comparing Kestrel Web Server vs IIS

IIS does almost everything. Kestrel does as little as possible. Because of this, Kestrel is much faster but also lacks a lot of functionality. I would think of Kestrel as really more of an application server. It is recommended to use another web server in front of it for public web applications. Kestrel is designed to run ASP.NET as fast as possible. It relies on a full fledged web server to do deal with things like security, management, etc.

Feature Comparison for Kestrel vs IIS

Here is an IIS vs Kestrel comparison of some key features. This should help you better understand the limitations of Kestrel. You can overcome these limitations by pairing it up with IIS or NGINX.

ASP.NET Core Hosting :: How to Use StructureMap with ASP.NET Core

$
0
0

This example shows how to use Structuremap dependency injection framework with ASP.NET Core instead of framework-level dependency injection.

ADDING STRUCTUREMAP TO ASP.NET CORE PROJECT

For Structuremap support in ASP.NET Core application we need two NuGet packages

  • StructureMap - core StructureMap package
  • StructureMap.Microsoft.DependencyInjection - adds support for ASP.NET Core

These packages are enough for getting StructureMap up and running.

DEMO SERVICES

For demo purposes let's define primitive messaging service interface and couple of implementations.

public interface IMessagingService
{
    string GetMessage();
}

public class BuiltInDiMessagingService : IMessagingService
{
    public string GetMessage()
    {
        return "Hello from built-in dependency injection!";
    }
}

public class StructuremapMessagingService : IMessagingService
{
    public string GetMessage()
    {
        return "Hello from Structuremap!";
    }
}

We need two implementations to demonstrate how built-in dependency injection is replaced by StructureMap.

DEFINING STRUCTUREMAP REGISTRY

StructureMap uses registry classes for defining dependencies. Direct definitions are also supported but for more complex applications we will write registries anyway. Here is our registry class.

public class MyStructuremapRegistry : Registry
{
    public MyStructuremapRegistry()
    {
        For<IMessagingService>().LifecycleIs(Lifecycles.Container)
                                .Use<StructuremapMessagingService>();
    }
}

ATTACHING STRUCTUREMAP TO ASP.NET CORE APPLICATION

StructureMap is attached to ASP.NET Core when application is starting up. We have to make three updates to ConfigureServices() method of StartUp class:

  • initialize and configure StructureMap container
  • make ConfigureServices return IServiceProvider
  • return IServiceProvider by StructureMap

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddTransient<IMessagingService, BuiltInDiMessagingService>();

    var container = new Container();

    container.Configure(config =>
    {
        config.AddRegistry(new MyStructuremapRegistry());
        config.Populate(services);
    });

    return container.GetInstance<IServiceProvider>();
}

Notice that there is also dependecy definition for framework-level dependency injection. Let's see which implementation wins.

TRYING OUT STRUCTUREMAP WITH ASP.NET CORE 2.0

Let's make some minor updates to Home controller and Index view to get message from injected service and display it on home page of sample application.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ASPNETCoreTemplate.Services;
using Microsoft.AspNetCore.Mvc;

namespace ASPNETCoreTemplate.Controllers
{
    public class HomeController : Controller
    {
        private readonly IMessagingService _messagingService;

        public HomeController (IMessagingService messagingService)
        {
            _messagingService = messagingService;
        }

        public IActionResult Index()
        {
            ViewData["Message"] = _messagingService.GetMessage();

            return View();
        }

        public IActionResult Error()
        {
            return View();
        }
    }
}

ASP.NET Core Hosting :: 5 Reasons to Use ASP.NET Core

$
0
0

When it comes to web application development, there are multiple technologies available to choose from. There are open-source technologies like Java & PHP, and then, there is closed-source technology ASP.NET MVC.

While millions of web developers use ASP.NET MVC to build web applications, but the latest ASP.NET Core framework offers far more benefits than the ASP.NET MVC for web application development.

ASP.NET Core is an open-source, cross-platform framework developed by both the Microsoft and its community. Basically, it is a complete reform of ASP.NET that combines MVC structure and Web API into a single framework.

Why Use ASP.NET Core for Web Application Development?

ASP.NET Core is an emerging, robust, and feature-rich framework that provides features to develop super-fast APIs for web apps.

Let’s take a look at the elements that make ASP.NET Core a right choice for Enterprise app development

1 — The MVC Architecture

Back in the days of the classic ASP.NET, developers had to worry about IsPostBack & ViewState. But with MVC, web application development has become more natural and the workflow also more efficient. In addition, the latest ASP.NET Core framework further helps in developing web APIs & web applications testable in better way, by achieving a clear separation of concerns.

In simple terms, ASP.NET Core makes it easier for developers to code, compile, and test something in either model, view, or the controller.

2 — Razor Pages

Razor Pages is a new element of ASP.NET Core that makes programming page-focused scenarios more productive. In technical terms, Razor Pages is a page-based coding model that makes building web UI easier.

If you’ve ever worked on ASP.NET MVC framework before, then you already know that the controller classes are filled with a large amount of actions. And not only that, but they also grow as the new things are added.

With Razor Pages, each web page becomes self-contained with its View component, and the code is also organized well together.

3 — Provides Support for Popular JavaScript Frameworks

Unlike ASP.NET MVC, the new .NET Core framework provides build-in templates for two most popular JavaScript frameworks — Angular & React (plus Aurelia).

The JavaScriptServices in the new ASP.NET Core provides an infrastructure that developers need to develop client-side apps using the above mentioned JavaScript frameworks.

The JavaScriptServices basically aims to eliminate underlying plumbing to allow developers start coding applications sooner, making it possible to build feature-rich front-end web applications.

4 — Improved Collaboration & Cross-Platform Support

ASP.NET Core is a cross-platform framework, meaning the apps build using this framework can run on Windows, Linux, and Mac Operating systems. In addition, the developers are also free to choose their development OS as well.

In simple terms, your developers can work across Linux, MacOS, or Windows and they can still collaborate on the same project. This is possible with unified experience offered by the Visual Studio IDE.

In short, the ASP.NET Core framework has the capacity to build & run web applications on Windows, Linux, and Mac OS.

5 — In-Built Dependency Injection Support

ASP.NET Core framework provides an in-built dependency injection, meaning you do not need rely on third-party frameworks like Ninject or AutoFactor anymore.

Dependency Injection is basically a pattern that can help developer distinguish the different pieces of their apps. Before the release of ASP.NET Core, the only way to get Dependency injection in any application was by using the above mentioned frameworks (Ninject, AutoFactor). But in ASP.NET Core, the dependency injection is treated as a first-class citizen. What this means is that developers are no longer limited to web applications, and they can leverage new libraries in more event-driven apps such as AWS Lambda or Azure Functions.

Overall, the dependency injection in the ASP.NET Core framework improves the testability and extensibility of web applications. 


ASP.NET Hosting :: Alternative Localization for Asp.Net Core Applications

$
0
0

Asp.Net Core Built-In Support

This is code fragment from official documentation how to localize content using built-in functionality.

App Content Localization

[Route("api/[controller]")]
public class AboutController : Controller
{
    private readonly IStringLocalizer<AboutController> _localizer;

    public AboutController(IStringLocalizer<AboutController> localizer)
    {
        _localizer = localizer;
    }

    [HttpGet]
    public string Get()
    {
        return _localizer["About Title"];
    }
}

And if you are working with Html content that shouldn't be escaped during rendering - you are using IHtmlLocalizerimplementation that returns LocalizedHtmlString instance.

public class BookController : Controller
{
    private readonly IHtmlLocalizer<BookController> _localizer;

    public BookController(IHtmlLocalizer<BookController> localizer)
    {
        _localizer = localizer;
    }

    public IActionResult Hello(string name)
    {
        ViewData["Message"] = _localizer["<b>Hello</b><i> {0}</i>", name];

        return View();
    }
}

View Localization

For the view localization - there is another injectable interface IViewLocalizer.

@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}

Alternative: Strongly-Typed DbLocalizationProvider

Where is my problem with built-in providers? They all are "stringly-typed". You have to provide string as either key or translation of the resource. I'm somehow more confident strongly-typed approach where I can use "Find All Usages", "Rename" or do any other static code operation that's would not be entirely possible in built-in approach.

Over the time I've been busy developing alternative localization provider for Asp.Net and Episerver (it's brilliant content management system) platforms specifically.

Thought getting that over to Asp.Net Core should not be hard. And it wasn't. So here we are - DbLocalizationProviderfor Asp.Net Core.

Getting Started

There are couple of things to setup first, before you will be able to start using strongly-typed localization provider.

First, you need to install the package (it will pull down other dependencies also).

PM> Install-Package LocalizationProvider.AspNetCore

Second you need to setup/configure services.
In your Startup.cs class you need to stuff related to Mvc localization (to get required services into DI container - service collection).

And then services.AddDbLocalizationProvider(). You can pass in configuration settings class and setup provider's behavior.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddLocalization();

        services.AddMvc()
                .AddViewLocalization()
                .AddDataAnnotationsLocalization();

        services.AddDbLocalizationProvider(cfg =>
        {
            cfg...
        });
    }
}

After then you will need to make sure that you start using the provider:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        ...
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        ...

        app.UseDbLocalizationProvider();
    }
}

Using localization provider will make sure that resources are discovered and registered in the database (if this process will not be disabled via AddDbLocalizationProvider() method).

App Content Localization

Localizing application content via IStringLocalizer<T> is similar as that would be done for regular Asp.Net applications.

You have to define resource container type:

[LocalizedResource]
public class SampleResources
{
    public string PageHeader => "This is page header";
}

Then you can demand IStringLocalizer<T> is any place you need that one (f.ex. in controller):

public class HomeController : Controller
{
    private readonly IStringLocalizer<SampleResources> _localizer;

    public HomeController(IStringLocalizer<SampleResources> localizer)
    {
        _localizer = localizer;
    }

    public IActionResult Index()
    {
        var smth = _localizer.GetString(r => r.PageHeader);
        return View();
    }
}

As you can see - you are able to use nice strongly-typed access to the resource type: _localizer.GetString(r => r.PageHeader);.

Even if you demanded strongly-typed localizer with specified container type T, it's possible to use also general/shared static resources:

[LocalizedResource]
public class SampleResources
{
    public static string SomeCommonText => "Hello World!";
    public string PageHeader => "This is page header";
}

public class HomeController : Controller
{
    private readonly IStringLocalizer<SampleResources> _localizer;

    public HomeController(IStringLocalizer<SampleResources> localizer)
    {
        _localizer = localizer;
    }

    public IActionResult Index()
    {
        var smth = _localizer.GetString(() => SampleResources.SomeCommonText);
        return View();
    }
}

View Localization

Regarding the views, story here is exactly the same - all built-in approach is supported:

@model UserViewModel
@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SampleResources> HtmlLocalizer

@Localizer.GetString(() => SampleResources.SomeCommonText)
@HtmlLocalizer.GetString(r => r.PageHeader)

Data Annotations

Supported. Sample:

[LocalizedModel]
public class UserViewModel
{
    [Display(Name = "User name:")]
    [Required(ErrorMessage = "Name of the user is required!")]
    public string UserName { get; set; }

    [Display(Name = "Password:")]
    [Required(ErrorMessage = "Password is kinda required :)")]
    public string Password { get; set; }
}

View.cshtml:

@model UserViewModel

<form asp-controller="Home" asp-action="Index" method="post">
    <div>
        <label asp-for="UserName"></label>
        <input asp-for="UserName"/>
        <span asp-validation-for="UserName"></span>
    </div>
    <div>
        <label asp-for="Password"></label>
        <input asp-for="Password" type="password"/>
        <span asp-validation-for="Password"></span>
    </div>
    ...
</form>

Localization in Libraries

You can either rely on IStringLocalizer implementation that's coming from Microsoft.Extensions.Localizationnamespace and demand that one in your injections:

using Microsoft.Extensions.Localization;
public class MyService
{
    public MyService(IStringLocalizer localizer)
    {
       ...
    }
}

Or you can also depend on LocalizationProvider class defined in DbLocalizationProvider namespace:

using DbLocalizationProvider;
public class MyService
{
    public MyService(LocalizationProvider provider)
    {
       ...
    }
}

Both of these types provide similar functionality in terms how to retrieve localized content.

Changing Culture

Sometimes you need to get translation for other language and not primary UI one.
This is possible either via built-in method:

@inject IHtmlLocalizer<SampleResources> Localizer

Localizer.WithCulture(new CultureInfo("no"))
         .GetString(() => SampleResources.SomeCommonText)

Or via additional extension method:

@inject IHtmlLocalizer<SampleResources> Localizer
Localizer.GetStringByCulture(() => SampleResources.SomeCommonText, new Culture("no"))

Stringly-Typed Localization

For backward compatibility or even if you wanna go hardcore and supply resource keys manually (for reasons) stingly-typed interface is also supported:

using Microsoft.Extensions.Localization;

public class MyService
{
    public MyService(IStringLocalizer localizer)
    {
       var header = localizer["MyProject.Resources.Header"];
    }
}

 

ASP.NET Core Hosting :: How to Add Custom Processing to Request in ASP.NET

$
0
0

When a request comes in to your ASP.NET site, it's routed through a series of message handlers (in ASP.NET Web API) or modules (in ASP.NET MVC), each of which performs some operation on the request. After a request is processed (presumably, by one of your Controllers), the response from your request goes through those handlers or modules again on its way back to the client.

Putting code in a handler or module allows you to perform some operation on every inbound request or outbound response. So, for example, if you want to customize security for your site, a good way to do that is to add your own module or handler to this chain. Alternatively, if you wanted to check data leaving your Web API site for "sensitive" information, a module or handler would be a good choice for that task, also.

The Limitations of ASP.NET Modules

Of the two technologies, ASP.NET MVC's HttpModules are the most limited. In many ways, modules are legacy technology dating from the beginnings of ASP.NET. However, this is the only option if you really do want to process every request to your site (including, for example, requests for image files and CSS files). You can even use HttpModules in Web API application.

The problem here is that the methods in a module are passed an HttpApplication object that has Context, Request and Response properties. These properties give you access to information about the request being made to your site and the response your site is returning. These are the same objects you have access to in your Controllers and, as in your Controllers, most of the properties on these objects are read-only. So, in an HttpModule you're limited to reading the incoming request or response or adding/removing headers on them.

Creating an HttpModule

Creating a module is a bit of a pain, also. First, you need to declare a class that implements the IHttpModule interface and give it a property called ModuleName that returns the name of your class as a string. You'll also need a Dispose method. Here's the start of a typical module:

public class GenericHttpModule : IHttpModule
{
  public String ModuleName
  {
    get
    {
      return "GenericHttpModule";
    }
  }
  public void Dispose() { }

Your next step is to add the Init method, which returns nothing but accepts an HttpApplication object. In this method, to process incoming requests, you need to wire up a method of your own to the HttpApplication object's BeginRequest method; if you want to process the outbound Response, you'll wire up your method to the object's EndRequest method. Here's an Init method that does both:

public void Init(HttpApplication application)
{
  application.BeginRequest += (new EventHandler(Inbound));
  application.EndRequest += (new EventHandler(Outbound));
}

The signatures of both the BeginRequest and EndRequest methods are the same: The methods are passed two parameters, one of type object and one of type EventArgs. The first parameter is the interesting one because it holds a reference to the HttpApplication object that holds the Context, Request and Response properties. The two methods I would need to work with the code in my Init method would look like this:

private void Inbound(Object source, EventArgs e)
{
  HttpApplication application = (HttpApplication)source;
  // ... process inbound request ...
}
private void Outbound(Object source, EventArgs e)
{
  HttpApplication application = (HttpApplication)source;
  // ... process outbound request ...            
}

You have one final thing to do: To have ASP.NET actually use your module, you need to tell your application about it. You do that in your web.config file with an add element, inside its modules element (IIS 7.0) or its httpModules element (IIS 6.0/IIS 7.0 running in Classic mode). The add element must reference both the name of your class and its type. This element would tie my sample module into the chain in IIS 7.0 (and would do the same in the httpModules element):

<modules> <add name="GenericHttpModule" type="HttpModulesAPI.GenericHttpModule"/>

The Basics of Handlers

Creating an ASP.NET Web API handler is, comparatively speaking, much simpler.

First, you must create a class that inherits from DelegatingHandler. Once you've done that, you override your class's SendAsync method. When a request hits your site, your SendAsync method will be passed the incoming request as an HttpRequestMessage. You have more flexibility here than you do with modules: you can add or remove headers or replace the message's content.

When you've done whatever you want with the incoming request, you call the base class's SendAsync method, passing the request message (there's also a cancellation token involved but I'll ignore it for simplicity's sake). Calling the base SendAsync method passes the request on to the next handler in the chain and, eventually, to your controller.

After your Controller has processed your request, the response message will be returned back through the chain of handlers as an HttpResponseMessage object. That means that your call to the base SendAsync method will, eventually, return the response from your Controller to your handler. Again, you can add or remove headers or replace the message's Content before returning the message to the ASP.NET process that called your delegating handler in the first place. Eventually, that response message will be delivered to the client that made the original request.

Here's the skeleton of a typical handler:

public class GenericMessageHandler : DelegatingHandler
{
  protected async override System.Threading.Tasks.Task<HttpResponseMessage>
          SendAsync(HttpRequestMessage request,
          System.Threading.CancellationToken cancellationToken)
  {
    //...work with HttpRequestMessage...
    HttpResponseMessage resp = await base.SendAsync(request, cancellationToken);
    //...work with HttpReqponseMessage
    return resp;
  }
}

And, in fact, you don't have to call the base SendAsync method at all -- there's nothing stopping you from creating an HttpResponseMessage in your SendAsync method and returning that.

Adding Your Handler to the Pipeline

To have your application use your handler, go to your App_Start folder, open the WebApiConfig file and add your new handler class to the config parameter's MessageHandlers class. This code, for example, adds my handler to the pipeline:

config.MessageHandlers.Add(new GenericMessageHandler());

But I have to be honest here: My experience has been that (outside of security) there are very few operations that I want to perform on every request to my ASP.NET Web API site. As a result, my typical handler begins with a bunch of If statements that check to see if this is a request that my handler should work with. In those scenarios, ASP.NET Web API gives me alternative: I can add the relevant handler just to the specific routes where it's needed.

To do that, I go to ASP.NET Web API's WebApiConfig file in the App_Start folder and add a fifth parameter to the MapHttpRoute method used to define routes (to use this parameter, you must provide a value for the constraints parameter on the method, even if all you provide is null). The handler parameter allows me to specify a DelegatingHandler to be used in processing requests and responses in that route. Here's an example with my GenericMessageHandler added to a route that grabs requests for my Customer controller (as this code shows, to tie my handler into the processing pipeline I also have to set its InnerHandler property to HttpControllerDispatcher):

config.Routes.MapHttpRoute(
                name: "CustomerApi",
                routeTemplate: "api/Customer/{id}",
                defaults: new { id = RouteParameter.Optional },
                constraints: null,                            
                handler: new GenericMessageHandler(){InnerHandler = new HttpControllerDispatcher(config) }
            );

I can, of course, selectively add this handler to multiple routes.

So if you want to add processing to every request that your site gets (or even just some of them), then you don't have to add code to every Controller or Action method in your project. You can, instead, bundle that code into either a module (for ASP.NET MVC) or a handler (for ASP.NET Web API).

ASP.NET Core Hosting :: How to Implement Action Filters in ASP.NET Core

$
0
0

Filters in .NET offer a great way to hook into the MVC action invocation pipeline. Therefore, we can use filters to extract code which can be reused and make our actions cleaner and maintainable. There are some filters that are already provided by .NET like the authorization filter, and there are the custom ones that we can create ourselves.

There are different filter types:

  • Authorization filters – They run first to determine whether a user is authorized for the current request
  • Resource filters – They run right after the authorization filters and are very useful for caching and performance
  • Action filters – They run right before and after the action method execution
  • Exception filters – They are used to handle exceptions before the response body is populated
  • Result filters – They run before and after the execution of the action methods result.

In this article, we are going to talk about Action filters and how to use them to create a cleaner and reusable code in our Web API’s.

Action Filters Implementation

To create an Acton filter, we need to create a class that inherits either from the IActionFilter interface or IAsyncActionFilter interface or from the ActionFilterAttribute class which is the implementation of the IActionFilterIAsyncActionFilter, and few different interfaces as well:

public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilterMetadata, IAsyncActionFilter, IResultFilter, IAsyncResultFilter, IOrderedFilter

In our examples, we are going to inherit from the IActionFIlter interface because it has all the method definitions we require.

To implement the synchronous Action filter that runs before and after action method execution, we need to implement OnActionExecuting and OnActionExecuted methods:

namespace ActionFilters.Filters
{
    public class ActionFilterExample : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // our code before action executes
        } 

        public void OnActionExecuted(ActionExecutedContext context)
        {
            // our code after action executes
        }
    }
}

We can do the same thing with an asynchronous filter by inheriting from IAsyncActionFilter, but we only have one method to implement the OnActionExecutionAsync:

namespace ActionFilters.Filters
{
    public class AsyncActionFilterExample : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            // execute any code before the action executes
            var result = await next();
            // execute any code after the action executes
        }
    }
}

The Scope of Action Filters

Like the other types of filters, the action filter can be added to different scope levels: Global, Action, Controller.

If we want to use our filter globally, we need to register it inside the AddMvc() method in the ConfigureServices method:

services.AddMvc(
  config =>
  {
     config.Filters.Add(new GlobalFilterExample());
  });

But if we want to use our filter as a service type on the Action or Controller level, we need to register it in the same ConfigureServices method but as a service in the IoC container:

services.AddScoped<ActionFilterExample>();
services.AddScoped<ControllerFilterExample>();

Finally, to use a filter registered on the Action or Controller level, we need to place it on top of the Controller or Action as a ServiceType:

namespace AspNetCore.Controllers
{
    [ServiceFilter(typeof(ControllerFilterExample))]
    [Route("api/[controller]")]
    public class TestController : Controller
    {
        [HttpGet]
        [ServiceFilter(typeof(ActionFilterExample))]
        public IEnumerable<string> Get()
        {
            return new string[] { "example", "data" };
        } 

    }
}

Order of Invocation

The order in which our filters are executed is as follows:

Of course, we can change the order of invocation by adding an additional property Order to the invocation statement:

namespace AspNetCore.Controllers
{
    [ServiceFilter(typeof(ControllerFilterExample), Order=2)]
    [Route("api/[controller]")]
    public class TestController : Controller
    {
        [HttpGet]
        [ServiceFilter(typeof(ActionFilterExample), Order=1)]
        public IEnumerable<string> Get()
        {
            return new string[] { "example", "data" };
        } 

    }
}

Or something like this on top of the same action:

[HttpGet]
[ServiceFilter(typeof(ActionFilterExample), Order=2)]
[ServiceFilter(typeof(ActionFilterExample2), Order=1)]
public IEnumerable<string> Get()
{
    return new string[] { "example", "data" };
}

Improving the Code with Action Filters

If we open the starting project from the AppStart folder from our repository, we can find the MoveController class in the Controllers folder. This controller has an implementation for all the CRUD operations. For the sake of simplicity, we haven’t used any additional layers for our API. 

Our actions are quite clean and readable without try-catch blocks due to global exception handling, but we can improve them even further.

The important thing to notice is that our Movie model inherits from the IEntity interface:

[Table("Movie")]
public class Movie: IEntity
{
    [Key]
    public Guid Id { get; set; }
    [Required(ErrorMessage = "Name is required")]
    public string Name { get; set; }
    [Required(ErrorMessage = "Genre is required")]
    public string Genre { get; set; }
    [Required(ErrorMessage = "Director is required")]
    public string Director { get; set; }
}

So let’s start with the validation code from the POST and PUT actions.

Validation with Action Filters

If we look at our POST and PUT actions, we can notice the repeated code in which we validate our Movie model:

if (movie == null)
{
     return BadRequest("Movie object is null");


if (!ModelState.IsValid)
{
     return BadRequest(ModelState);
}

We can extract that code into a custom Action Filter class, thus making this code reusable and the action cleaner.

So let’s do that.

Let’s create a new folder in our solution explorer, and name it ActionFilters. Then inside that folder, we are going to create a new class ValidationFilterAttribute:

using Microsoft.AspNetCore.Mvc.Filters; 

namespace ActionFilters.ActionFilters
{
    public class ValidationFilterAttribute : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {            

        } 

        public void OnActionExecuted(ActionExecutedContext context)
        {            

        }
    }
}

Now we are going to modify the OnActionExecuting method to validate our model:

using ActionFilters.Contracts;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Linq; 

namespace ActionFilters.ActionFilters
{
    public class ValidationFilterAttribute : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext context)
        {
            var param = context.ActionArguments.SingleOrDefault(p => p.Value is IEntity);
            if(param.Value == null)
            {
                context.Result = new BadRequestObjectResult("Object is null");
                return;
            }            

            if(!context.ModelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        } 

        public void OnActionExecuted(ActionExecutedContext context)
        {          
        }
    }
}

Next, let’s register this action filter in the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
       services.AddDbContext<MovieContext>(options =>
           options.UseSqlServer(Configuration.GetConnectionString("sqlConString"))); 

       services.AddScoped<ValidationFilterAttribute>(); 

       services.AddMvc();
}

Finally, let’s remove that validation code from our actions and call this action filter as a service:

[HttpPost]
[ServiceFilter(typeof(ValidationFilterAttribute))]
public IActionResult Post([FromBody] Movie movie)
{
     _context.Movies.Add(movie);
     _context.SaveChanges(); 

     return CreatedAtRoute("MovieById", new { id = movie.Id }, movie);


[HttpPut("{id}")]
[ServiceFilter(typeof(ValidationFilterAttribute))]
public IActionResult Put(Guid id, [FromBody]Movie movie)
{
    var dbMovie = _context.Movies.SingleOrDefault(x => x.Id.Equals(id));
    if (dbMovie == null)
    {
        return NotFound();
    } 

    dbMovie.Map(movie); 

    _context.Movies.Update(dbMovie);
    _context.SaveChanges(); 

    return NoContent();
}

Excellent.

This code is much cleaner and more readable now without the validation part. And furthermore, the validation part is now reusable as long as our model classes inherit from the IEntity interface, which is a quite common behavior.

If we send a POST request for example with the invalid model we will get the BadRequest response:

Dependency Injection in Action Filters

If we take a look at our GetById, POST and PUT actions, we are going to see the code where we fetch the move by id from the database and check if it exists:

var dbMovie = _context.Movies.SingleOrDefault(x => x.Id.Equals(id));
if (dbMovie == null)
{
     return NotFound();
}

That’s something we can extract to the Action Filter class as well, thus making it reusable in all the actions.

Of course, we need to inject our context in a new ActionFilter class by using dependency injection.

So, let’s create another Action Filter class ValidateEntityExistsAttribute in the ActionFilters folder and modify it:

using System.Linq; 

namespace ActionFilters.ActionFilters
{
    public class ValidateEntityExistsAttribute<T> : IActionFilter where T: class, IEntity
    {
        private readonly MovieContext _context; 

        public ValidateEntityExistsAttribute(MovieContext context)
        {
            _context = context;
        } 

        public void OnActionExecuting(ActionExecutingContext context)
        {
            Guid id = Guid.Empty; 

            if (context.ActionArguments.ContainsKey("id"))
            {
                id = (Guid)context.ActionArguments["id"];
            }
            else
            {
                context.Result = new BadRequestObjectResult("Bad id parameter");
                return;
            } 

            var entity = _context.Set<T>().SingleOrDefault(x => x.Id.Equals(id));    
            if(entity == null)
            {
                context.Result = new NotFoundResult();
            }
            else
            {
                context.HttpContext.Items.Add("entity", entity);
            }
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
        }
    }
}

We’ve created this Action Filter class to be generic so that we could reuse it for any model in our project. Furthermore, if we find the entity in the database, we store it in HttpContext because we need that entity in our action methods and we don’t want to query the database two times (we would lose more than we gain if we double that action).

Now let’s register it:

services.AddScoped<ValidateEntityExistsAttribute<Movie>>();

And let’s modify our actions:

[HttpGet("{id}", Name = "MovieById")]
[ServiceFilter(typeof(ValidateEntityExistsAttribute<Movie>))]
public IActionResult Get(Guid id)
{
    var dbMovie = HttpContext.Items["entity"] as Movie; 

    return Ok(dbMovie);
}
[HttpPut("{id}")]
[ServiceFilter(typeof(ValidationFilterAttribute))]
[ServiceFilter(typeof(ValidateEntityExistsAttribute<Movie>))]
public IActionResult Put(Guid id, [FromBody]Movie movie)
{
    var dbMovie = HttpContext.Items["entity"] as Movie; 

     dbMovie.Map(movie); 

     _context.Movies.Update(dbMovie);
     _context.SaveChanges(); 

     return NoContent();


[HttpDelete("{id}")]
[ServiceFilter(typeof(ValidateEntityExistsAttribute<Movie>))]
public IActionResult Delete(Guid id)
{
    var dbMovie = HttpContext.Items["entity"] as Movie; 

     _context.Movies.Remove(dbMovie);
     _context.SaveChanges(); 

     return NoContent();
}

Awesome.

Now our actions look great without code repetition, try-catch blocks or additional fetch request towards the database.

Conclusion

Thank you for reading this article. We hope you have learned new useful things.

As we already said, we always recommend using Action Filters because they give us reusability in our code and cleaner code in our actions as well.

ASP.NET Core Hosting :: How to Set Headers and HTTP Status Codes in ASP.NET Core

$
0
0

I was working on an interesting issue in an ASP.NET Core recently. An external framework was responsible for creating an HTTP Response, and I was only in control of a little component that customized some internal behaviours (via a relevant extensibility point), without being able to influence the final response sent over HTTP.

This is common if you think about extending things like CMS systems or specialized services like for example Identity Server. In those situations, more often than not, the framework would be highly opinionated in what it is trying to do at the HTTP boundaries and as a result, trying to override the HTTP status codes or headers it produces may not be easy.

Let’s have a look at a simple generic workaround.

TL;DR

In ASP.NET Core you can hook a callback to the HTTP response object, which allows you to run arbitrary code just before the response starts getting sent or as soon as it has been sent. This allows you to override status code, headers or even change the response body even if your code is not responsible for flushing the response

// always set the status code to 418
response.OnStarting(() =>
{
    response.StatusCode = 418;
    return Task.CompletedTask;
});

The problem

To illustrate the problem better, let’s have a look at a concrete example – and I think Identity Server is a good choice here.

Identity Server allows you to register your own validators for various authentication grant types – for example client credentials grant, resource owner or even your own custom extension grant.

An implementation of such custom validator could like this:

public class MyResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {
        var user = await UserStore.FindAndValidate(context.UserName, context.Password); 

        if (user == null || !user.IsValid())
        {
            // reject as the credentials are incorrect or account invalid
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, "Invalid username or password.");
            return;
        }        

        if (!user.IsCountrySupported())
        {
            // reject as the country of the user is not allowed
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, "Country not supported.");
            return;
        }        

        // allow
        context.Result = new GrantValidationResult(user.Id, "password", user.Claims, "idsrv");
    }
}

In other words, we validate the user, and allow the token to be issued if the username and password are correct. If not, we will produce a token request error; in addition to that we also produce a different error if the user credentials are correct but the country is not supported.

This is all nice and fine. We have no touchpoints to the HTTP response here, as Identity Server (or any other framework/service that we might be using) would take care of that for us. We only produce the result that we are mandated to produce by the contract – a GrantValidationResult in this case.

It works well in most situations. However, let’s imagine that we’d like to influence the HTTP status codes being returned from this validation code. At the moment the status codes are hidden from us, and it is the responsibility of Identity Server to produce them.

In our case, the Identity Server would actually be returning 2 different ones:

  • GrantValidationResult(user.Id, “password”, user.Claims, “idsrv”) would obviously produce a 200 and result in a token being sent to the user
  • GrantValidationResult(TokenRequestErrors.InvalidRequest, “{ERROR DESCRIPTION}”) would produce a 400 and convey the error description to the caller in the error_description JSON property of the response (as defined by the spec).

Now let’s imagine the situation, that for the code path of user.IsCountrySupported(), we’d like to use HTTP status code 451 instead. This is allowed by the spec, which states “the authorization server responds with an HTTP 400 (Bad Request) status code (unless specified otherwise)”. However, such status code customization is currently not supported by Identity Server.

Let’s have a look at addressing this via a neat ASP.NET Core feature. Before we get there – in case you don’t agree with this spec interpretation – remember that this is merely an example to illustrate that ASP.NET Core feature.

Wrong way to deal with it

There are several ideas of dealing with this, that come to mind straight away.

One naive approach would be to try to throw an exception, let it bubble up as far as possible and then handle it in a way that you can convert the response to the relevant HTTP status code (perhaps with a global handler registered in your Startup class). This, however, wouldn’t work with Identity Server, as it handles all exceptions in the pipeline on its own, without letting it bubble up. In fact, this would typically be the case with most frameworks or services of that sort, not to mention using exceptions for flow control is iffy at best.

Another approach could be to try to write a middleware component, that runs at the end of HTTP pipeline (so wraps the Identity Server middleware) and use it to change the status code. This seems like a great idea at first, but unfortunately it wouldn’t work.

The reason for that is that ASP.NET Core would flush the headers of the response as soon as the first body write happens, and Identity Server, in its pipeline, would start writing to the body already. This means that even though you can technically (there would be no exception thrown for that) change the status code on the response, or inject some headers into it using a custom middleware that runs at the end of the pipeline, that would have no effect on the response anymore, as it is simply too late. You can actually normally see that on the response object by inspecting the response.HasStarted property – at that moment status code and headers modifications are not possible anymore.

One other idea could be to hijack the response writing completely. Since you can inject IHttpContextAccessor to any class, anywhere in the ASP.NET Core application, you can fairly easily get a hold of the HttpResponse. This allows you to simply write to the HTTP response directly. Such approach could possibly work but it is not very elegant to say the least. It would require you to correctly produce the entire set of headers (also the more esoteric ones like Cache-Control and so on) and the status code correctly and flush it before Identity Server can do that, allowing it to only complete the response by writing the body. This is very error prone and very unmaintainable.

Simple solution

A simple and elegant solution is to leverage a little known feature of ASP.NET Core – the ability to register your own callback on the HttpResponse, that would run as soon as the response is started to be sent (or as soon as its completed).

The following hooks exist on the HttpResponse:

/// <summary>
/// Adds a delegate to be invoked just before response headers will be sent to the client.
/// </summary>
/// <param name="callback">The delegate to execute.</param>
/// <param name="state">A state object to capture and pass back to the delegate.</param>
public abstract void OnStarting(Func<object, Task> callback, object state); 

/// <summary>
/// Adds a delegate to be invoked just before response headers will be sent to the client.
/// </summary>
/// <param name="callback">The delegate to execute.</param>
public virtual void OnStarting(Func<Task> callback) => OnStarting(_callbackDelegate, callback); 

/// <summary>
/// Adds a delegate to be invoked after the response has finished being sent to the client.
/// </summary>
/// <param name="callback">The delegate to invoke.</param>
/// <param name="state">A state object to capture and pass back to the delegate.</param>
public abstract void OnCompleted(Func<object, Task> callback, object state); 

/// <summary>
/// Adds a delegate to be invoked after the response has finished being sent to the client.
/// </summary>
/// <param name="callback">The delegate to invoke.</param>
public virtual void OnCompleted(Func<Task> callback) => OnCompleted(_callbackDelegate, callback);

This means we can simply register a delegate that would change the HTTP Status Code, modify the headers and possibly even meddle with the response body, from any point in the ASP.NET Core application. Then, as soon as the response starts being sent (irrespective to the fact which component or part of the pipeline triggered that), our code would run, allowing us to influence the structure of that response.

It is extremely convenient, as we are able to create de facto extensibility points for 3rd party applications, frameworks or services (like Identity Server), in places where they normally don’t exist.

In our case, the final code looks like this:

public static class HttpResponseExtensions
{
    public static void SetHttpStatusCodeOverride(this HttpResponse response, int httpStatusCode)
    {
        response.OnStarting(() =>
        {
            response.StatusCode = httpStatusCode;
            return Task.CompletedTask;
        });
    }


public class MyResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
   private readonly IHttpContextAccessor _httpContextAccessor;  

   public MyResourceOwnerPasswordValidator(IHttpContextAccessor httpContextAccessor)
   {
       _httpContextAccessor = httpContextAccessor;
   } 

    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {
        var user = await UserStore.FindAndValidate(context.UserName, context.Password); 

        if (user == null || !user.IsValid())
        {
            // default 400
            // reject as the credentials are incorrect or account invalid
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, "Invalid username or password.");
            return;
        }        

        if (!user.IsCountrySupported())
        {
            // overridden to 451
            // reject as the country of the user is not allowed
           _httpContextAccessor.HttpContext.Response.SetHttpStatusCodeOverride(451);
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, "Country not supported.");
            return;
        }        

        // allow
        context.Result = new GrantValidationResult(user.Id, "password", user.Claims, "idsrv");
    }
}

I hope you will find this technique useful – I used Identity Server as an example, because it actually solves a real world problem here – but I think you could apply this approach in various places where you’d like to have a certain response-based extensibility point and it’s simply not available.

ASP.NET Core Hosting :: How to Send and Receive Email in ASP.NET Core Using Mailkit

$
0
0

Creating An Email Service

It’s always good practice that when you add in a new library, that you build an abstraction on top of it. If we take MailKit as an example, what if MailKit is later superceded by a better emailing library? Will we have to change references all over our code to reference this new library? Or maybe MailKit has to make a breaking change between versions, will we then have to go through our code fixing all the now broken changes?

Another added bonus to creating an abstraction is that it allows us to map out how we want our service to look before we worry about implementation details. We can take a very high level view of sending an email for instance without having to worry about exactly how MailKit works. Because there is a lot of code to get through, I won’t do too much explaining at this point, we will just run through it. Let’s go!

First, let’s go ahead and create an EmailAddress class. This will have only two properties that describe an EmailAddress.

public class EmailAddress
{
                public string Name { get; set; }
                public string Address { get; set; }
}

Now we will need something to describe a simple EmailMessage. There are a tonne of properties on an email, for example attachments, CC, BCC, headers etc but we will break it down to the basics for now. Containing all of this within a class means that we can add extra properties as we need them later on.

public class EmailMessage
{
                public EmailMessage()
                {
                                ToAddresses = new List<EmailAddress>();
                                FromAddresses = new List<EmailAddress>();
               

                public List<EmailAddress> ToAddresses { get; set; }
                public List<EmailAddress> FromAddresses { get; set; }
                public string Subject { get; set; }
                public string Content { get; set; }
}

Now we need to setup our email configuration. That’s our SMTP servers, ports, credentials etc. For this we will make a simple settings class to hold all of this. Since we are good programmers we will use an interface too!

public interface IEmailConfiguration
{
                string SmtpServer { get; }
                int SmtpPort { get; }
                string SmtpUsername { get; set; }
                string SmtpPassword { get; set; } 

                string PopServer { get; }
                int PopPort { get; }
                string PopUsername { get; }
                string PopPassword { get; }


public class EmailConfiguration : IEmailConfiguration
{
                public string SmtpServer { get; set; }
                public int SmtpPort  { get; set; }
                public string SmtpUsername { get; set; }
                public string SmtpPassword { get; set; } 

                public string PopServer { get; set; }
                public int PopPort { get; set; }
                public string PopUsername { get; set; }
                public string PopPassword { get; set; }
}

Now we actually need to load this configuration into our app. In your appsettings.json, you need to add a section at the root for email settings. It should look something like this :

{
  "EmailConfiguration": {
    "SmtpServer": "smtp.myserver.com",
    "SmtpPort": 465,
    "SmtpUsername": "smtpusername",
    "SmtpPassword": "smtppassword", 

    "PopServer": "popserver",
    "PopPort": 995,
    "PopUsername": "popusername",
    "PopPassword" :  "poppassword"
  }
  ....Other settings here...
}

In the ConfigureServices method or your startup.cs, we can now pull out this configuration and load it into our app with a single line.

public void ConfigureServices(IServiceCollection services)
{
                services.AddMvc();

services.AddSingleton<IEmailConfiguration>(Configuration.GetSection("EmailConfiguration").Get<EmailConfiguration>());
}

This allows us to inject our configuration class anywhere in our app.

The final piece of the puzzle is a simple email service that can be used to send and receive email. Let’s create an interface and an implementation that’s empty for now. The implementation should accept our settings object as a constructor.

public interface IEmailService
{
                void Send(EmailMessage emailMessage);
                List<EmailMessage> ReceiveEmail(int maxCount = 10);


public class EmailService : IEmailService
{
                private readonly IEmailConfiguration _emailConfiguration;

                public EmailService(IEmailConfiguration emailConfiguration)
                {
                                _emailConfiguration = emailConfiguration;
               

                public List<EmailMessage> ReceiveEmail(int maxCount = 10)
                {
                                throw new NotImplementedException();
               

                public void Send(EmailMessage emailMessage)
                {
                                throw new NotImplementedException();
                }
}

Head back to our ConfigureServices method of our startup.cs to add in a final line to inject in our EmailService everywhere.

public void ConfigureServices(IServiceCollection services)
{
                services.AddMvc();
services.AddSingleton<IEmailConfiguration>(Configuration.GetSection("EmailConfiguration").Get<EmailConfiguration>());
                services.AddTransient<IEmailService, EmailService>();
}

Phew! And we are done. If at this point we decided MailKit isn’t for us, we still have an email service that can swap in and out libraries as it needs to, and our calling application doesn’t need to worry about what’s going on under the hood. That’s the beauty of abstracting a library away!

Getting Started With MailKit

Getting started with MailKit is as easy as installing a Nuget package. Simply run the following from your Package Manager Console :

Install-Package MailKit

And hey presto! You now have access to MailKit in your application

Sending Email via SMTP With MailKit

Let’s head back to our email service class and fill out the “Send” method with the actual code to send an email via MailKit. The code to do this is below :

public void Send(EmailMessage emailMessage)
{
                var message = new MimeMessage();
                message.To.AddRange(emailMessage.ToAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
                message.From.AddRange(emailMessage.FromAddresses.Select(x => new MailboxAddress(x.Name, x.Address))); 

                message.Subject = emailMessage.Subject;
                //We will say we are sending HTML. But there are options for plaintext etc.
                message.Body = new TextPart(TextFormat.Html)
                {
                                Text = emailMessage.Content
                }; 

                //Be careful that the SmtpClient class is the one from Mailkit not the framework!
                using (var emailClient = new SmtpClient())
                {
                                //The last parameter here is to use SSL (Which you should!)
                                emailClient.Connect(_emailConfiguration.SmtpServer, _emailConfiguration.SmtpPort, true); 

                                //Remove any OAuth functionality as we won't be using it.
                                emailClient.AuthenticationMechanisms.Remove("XOAUTH2"); 

                                emailClient.Authenticate(_emailConfiguration.SmtpUsername, _emailConfiguration.SmtpPassword); 

                                emailClient.Send(message);
                                emailClient.Disconnect(true);
                }                             

}

The comments should be pretty self explanatory, but let’s quickly run through it.

  • You can send clear text or HTML emails depending on the “TextFormat” you use when creating your message body
  • MailKit has named it’s Smtp class “SmtpClient” which is the same as the framework class. Be careful if you are using Resharper and the like that when you click “Add Reference” you are adding the correct reference.
  • You should choose to use SSL whenever available when connecting to the SMTP Server

Because we built out our EmailService, EmailMessage and EmailConfiguration classes earlier, they are all ready to be used immediately!

Receiving Email via POP With MailKit

And now the code to receive email via POP.

public List<EmailMessage> ReceiveEmail(int maxCount = 10)
{
                using (var emailClient = new Pop3Client())
                {
                                emailClient.Connect(_emailConfiguration.PopServer, _emailConfiguration.PopPort, true); 

                                emailClient.AuthenticationMechanisms.Remove("XOAUTH2"); 

                                emailClient.Authenticate(_emailConfiguration.PopUsername, _emailConfiguration.PopPassword); 

                                List<EmailMessage> emails = new List<EmailMessage>();
                                for(int i=0; i < emailClient.Count && i < maxCount; i++)
                                {
                                                var message = emailClient.GetMessage(i);
                                                var emailMessage = new EmailMessage
                                                {
                                                                Content = !string.IsNullOrEmpty(message.HtmlBody) ? message.HtmlBody : message.TextBody,
                                                                Subject = message.Subject
                                                };
                                                emailMessage.ToAddresses.AddRange(message.To.Select(x => (MailboxAddress)x).Select(x => new EmailAddress { Address = x.Address, Name = x.Name }));
                                                emailMessage.FromAddresses.AddRange(message.From.Select(x => (MailboxAddress)x).Select(x => new EmailAddress { Address = x.Address, Name = x.Name }));
                               

                                return emails;
                }
}

Again, all rather straight forward.

While we only retrieve a few basic details about the email message, the actual MailKit email object has a tonne of data you can inspect including headers, CC addresses, etc. Extend as you need to!

ASP.NET Core 3 Hosting :: ASP.NET Core 3 Preview

$
0
0

ASP.NET Core 3.0 App with .NET Core 3.0 preview 2 release

Before we create the application, first we need to install Visual Studio 2019 and .NET Core 3.0. Let’s first install .NET Core 3.0 SDK.

Installing .NET Core 3.0

To download .NET Core 3.0 preview 2, visit this link. Based on your platform, download the appropriate installer. Once the download is complete, run the installer to install .NET Core 3.0 on your system. The .NET Core 3.0 preview installation will not impact your existing .NET Core version installation.

Installing Visual Studio 2019 Preview

To install Visual Studio 2019 preview, download the installer from this location. Don’t worry. Visual Studio and Visual Studio “Preview” can be installed side-by-side on the same device. It will have no impact on your current stable VS installation.

Visual Studio 2019 offers a completely new project creation experience. Once the installation is complete, let’s open the Visual Studio 2019 preview and create the ASP.NET Core 3.0 app. Select the ASP.NET Core Web Application template.

When you click Ok, you will get the following prompt. Select ASP.NET Core 3.0 and choose the MVC template.

The Visual Studio will create an ASP.NET Core 3.0 based MVC project. The solution structure looks similar to the previous version of ASP.NET Core. However, there is one change with respect to dependencies reference, which is the Microsoft.AspNetCore.Mvc.NewtonsoftJson nuget package.

 

ASP.NET Core shared framework (Microsoft.AspNetCore.App) will only contain first-party assemblies that are fully developed, supported, and serviceable by Microsoft. As part of this change, the following sub-components will be removed from shared framework.

  • Json.NET (Newtonsoft.Json)
  • Entity Framework Core (Microsoft.EntityFrameworkCore.*)
  • Microsoft.CodeAnalysis (Roslyn)

The project file is now targeting to .NET Core 3.0 and also has a reference of Microsoft.AspNetCore.Mvc.NewtonsoftJson package.

<Project Sdk="Microsoft.NET.Sdk.Web"> 

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup> 

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview-19075-0444" />
  </ItemGroup> 

</Project>

Let’s take a look at the code level changes.

1. Open the Program.cs and you will see the following code. The ASP.NET Core 3.0 templates use Generic Host. Previous versions used Web Host.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    } 

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

The goal of the Generic Host is to decouple the HTTP pipeline from the Web Host API to enable a wider array of host scenarios. Messaging, background tasks, and other non-HTTP workloads based on the Generic Host benefit from cross-cutting capabilities, such as configuration, dependency injection (DI), and logging.

The above code uses webBuilder which is a type of IWebHostBuilder interface used with WebHostBuilder. But it will be deprecated and eventually its functionality will be replaced by HostBuilder, though the interface will remain.

The biggest difference between WebHostBuilder and HostBuilder is that you can no longer inject arbitrary services into your Startup.cs. Instead, you will be limited to the IHostingEnvironment and IConfiguration interfaces. This removes a behavior quirk related to injecting services into Startup.cs before the ConfigureServices method is called.

2. As mentioned earlier, Json.NET is removed from the shared framework and now needs to be added as a package. Open Startup.cs and take a look at ConfigureServices method

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()
        .AddNewtonsoftJson();
}

3. There are some updates to EndPoint routing introduced with ASP.NET Core 2.2. Endpoint routing allows frameworks like MVC as well as other routable things to mix with middleware in a way that hasn’t been possible before. With this, routing decisions can occur earlier into the pipeline so that incoming requests can be mapped to their eventual endpoint before MVC is even invoked. This is now present in the project templates in 3.0.0-preview-2 (Startup.cs -> Configure()).

app.UseRouting(routes =>
{
     routes.MapApplication();
     routes.MapControllerRoute(
         name: "default",
         template: "{controller=Home}/{action=Index}/{id?}");
});

Here, the app.UseRouting() call adds a new Endpoint Routing middleware. The UseRouting replaces many of the features that were implemented inside UseMvc() in the past. The MapApplication() brings in MVC controllers and pages for routing and MapControllerRoutedefines the default route.

That’s it for now

Summary

ASP.NET Core 3.0 will bring some code breaking changes and some of them are available with this preview 2 release. The change regarding ASP.NET Core shared framework to include only those libraries which are developed, supported, and serviceable by Microsoft will definitely reduce the application size by a few bytes. It is the right time to play around ASP.NET Core 3.0 and expect some more changes when the final version comes out.

ASP.NET Core MVC Hosting :: Dependency Injection Into Actions in ASP.NET Core MVC 2.1

$
0
0

In this tutorial, we will see configuration about dependency injection into actions in ASP.NET Core MVC 2.1

The basic idea

Just in case what we are trying to achieve here is not obvious yet, here is an extremely basic layout of the problem. Let’s imagine having two separate services, with two separate implementations.

public interface IHelloService
{
    string SayHello();
}
public class HelloService : IHelloService
{
    public string SayHello() => "Hello";


public interface IGoodbyeService
{
    string SayGoodbye();


public class GoodbyeService : IGoodbyeService
{
    public string SayGoodbye() => "Bye";
}

For the sake of completeness, let’s also include a basic request DTO. It’s not needed at all, but I want to have it just to be able to illustrate that injecting dependencies as parameters will not interfere with regular binding process.

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

We’d like to consume them in a controller, but rather than doing this

public class GreetController : ApiController
{
    private readonly IHelloService _helloService;
    private readonly IGoodbyeService _goodbyeService; 

    public GreetController(IHelloService helloService, IGoodbyeService goodbyeService)
    {
        _helloService = helloService;
        _goodbyeService = goodbyeService;
    } 

    [HttpPost("hello")]
    public string Post(RequestDto input)
        => _helloService.SayHello() + " " + input.Name;        

    [HttpPost("bye")]      
    public string Post(RequestDto input)
        => _goodbyeService.SayGoodbye() + " " + input.Name;
}

I would want to see the following setup:

[Route("api/[controller]")]
[ApiController]
public class GreetController : ApiController
{
    [HttpPost("hello")]
    public ActionResult<string> Post(RequestDto input, IHelloService svc)
        => svc.SayHello() + " " + input.Name;        

    [HttpPost("bye")]      
    public ActionResult<string> Post(RequestDto input, IGoodbyeService svc)
        => svc.SayGoodbye() + " " + input.Name;
}

Note that the [ApiController] and ActionResult<T> were introduced in ASP.NET Core 2.1. They will actually impact the discussion, but more on that later.

Injection into actions

As I mentioned earlier, contrary to i.e. ASP.NET Web API, where we needed to override some internal components to make this, the basic scenario laid out here works out of the box in ASP.NET Core. The only caveat is that you have to decorate the parameter that you’d like to inject (resolve from the DI container) with a [FromServices] attribute.

[HttpPost("hello")]
public ActionResult<string> Post(RequestDto input, [FromServices]IHelloService svc)
     => svc.SayHello() + " " + input.Name;

We could finish the discussion here, as the goal is pretty much achieved. For example, I could issue a following request

curl -X POST \
  https://localhost:5001/api/greet/hello \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/json' \
  -d '{
"name":"jervis"
}'

and then get the following response:

Hello jervis

However, it is still possible to get rid of the [FromServices] attribute by establishing a reasonable convention. For example, we could easily detect at application startup, when the application model is composed, if a parameter is an interface, and if that’s the case, we would resolve it from the container.

In the past, in ASP.NET Core 2.0, this could be achieved by building an IApplicationModelConvention, registering it, iterating over all discovered controller, then over their actions and then over their parameters, and inspecting those. Then, marking the parameters we’d want to resolve from the DI container with a BindingSource.Services.

This would partially work in ASP.NET Core 2.1 too, however only if you wouldn’t use the new ApiControllerAttribute feature. That feature would validate whether your actions doesn’t inject more than one unannotated complex parameter into an action (which is essentially what we are doing) and throw an exception if that’s the case. That validation happens before our convention would run. The reason for this is that the ApiControllerAttribute feature is implemented as an IApplicationModelProvider which does similar stuff too IApplicationModelConvention – but providers run before the conventions do. So to address that we’d implement a custom provider instead.

public class ActionDependencyModelProvider : IApplicationModelProvider
{
    public int Order => -901; 

    public void OnProvidersExecuted(ApplicationModelProviderContext context)
    {
    } 

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        foreach (var controllerModel in context.Result.Controllers)
        {
            foreach(var actionModel in controllerModel.Actions)
            {
                foreach(var parameterModel in actionModel.Parameters)
                {
                    if (parameterModel.ParameterType.IsInterface)
                    {
                        parameterModel.BindingInfo = new BindingInfo()
                        {
                            BindingSource = BindingSource.Services
                        };
                    }
                }
            }
        }
    }
}

Two implementation notes here – I used the Order value of -901 – that’s because the provider responsible for ApiControllerAttribute uses the value -900 and we’d want to run before it. Another thing is that we check for a parameter being an interface to resolve it from the DI container. Of course you are free to establish your own convention here (especially as it’s perfectly reasonable to have non-interface based dependencies). For example you could have a simple convention that 1st parameter would be bound from body and next ones from the container, or a convention where the assembly from which the Type comes dictates whether it’s a request model or a dependency, or simply some naming convention.

You’d just have to register this provider at startup, and that’s it. In our case the Startup registrations now look like this:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IHelloService, HelloService>();
    services.AddSingleton<IGoodbyeService, GoodbyeService>(); 

    services.TryAddEnumerable(
        ServiceDescriptor.Transient<IApplicationModelProvider, ActionDependencyModelProvider>());
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

And that’s it – you can now use your dependencies exactly as we defined it earlier:

[Route("api/[controller]")]
[ApiController]
public class GreetController : ApiController
{
    [HttpPost("hello")]
    public ActionResult<string> Post(RequestDto input, IHelloService svc)
        => svc.SayHello() + " " + input.Name;        

    [HttpPost("bye")]      
    public ActionResult<string> Post(RequestDto input, IGoodbyeService svc)
        => svc.SayGoodbye() + " " + input.Name;
}


ASP.NET Core Hosting :: How to Access HttpContext Outside of Framework Components in ASP.NET Core

$
0
0

When developing web applications with ASP.NET, it is common to end up in situations where you require access to HttpContext. This wouldn’t be anything special, but outside of the context of framework level APIs such as controllers, middleware and so on (which would always give you a way to fetch the current HttpContext), it can be tricky.

While generally speaking, HttpContext could be passed around as a regular dependency to the logical components that require it, that solution is often impractical.

Let’s have a look at how you can get a hold of HttpContext in ASP.NET Core.

HttpContextAccessor

ASP.NET Core provides a convenience interface, IHttpContextAccessor (and it’s default implementation, HttpContextAccessor) in order to simplify accessing HttpContext. It must be registered at application startup inside the IServicesCollection and once it’s there, the framework will make sure that you can inject it anywhere you need, and use it to access the current instance of HttpContext.

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

HttpContextAccessor under the hood

So how does it work? Consider piece of code you can find in any ASP.NET Core template:

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseStartup<Startup>()
                .Build(); 

            host.Run();
        }
    }

It provides the launch point of your application. This is going to start the server and boostrap all the necessary services, including building up the request processing pipeline from your Startup class.

Internally, in the process of that bootstrapping, that code will wire in the relevant server (Kestrel) and will create an instance of HostingApplication and pass into it an implementation of IHttpContextFactory (more on that later).

HostingApplication is an implementation of IHttpApplication which exposes three methods:

    public interface IHttpApplication<TContext>
    {
        /// <summary>
        /// Create a TContext given a collection of HTTP features.
        /// </summary>
        /// <param name="contextFeatures">A collection of HTTP features to be used for creating the TContext.</param>
        /// <returns>The created TContext.</returns>
        TContext CreateContext(IFeatureCollection contextFeatures); 

        /// <summary>
        /// Asynchronously processes an TContext.
        /// </summary>
        /// <param name="context">The TContext that the operation will process.</param>
        Task ProcessRequestAsync(TContext context); 

        /// <summary>
        /// Dispose a given TContext.
        /// </summary>
        /// <param name="context">The TContext to be disposed.</param>
        /// <param name="exception">The Exception thrown when processing did not complete successfully, otherwise null.</param>
        void DisposeContext(TContext context, Exception exception);
    }

The server that we are using (say, Kestrel), on each incoming request, will use the above interface to call CreateContext and later on ProcessRequestAsync.

The former method is where IHttpContextFactory will be used to initialize HttpContext instance, and that instance will live throughout the lifetime of the HTTP request. The default implementation of IHttpContextFactory will look into the DI container, and check if IHttpContextAccessor is there. If it is, then it will “share” its HttpContext instance with the accessor.

The HttpContextAccessor will then store the HttpContext using System.Runtime.Remoting.Messaging.CallContext on desktop CLR and using System.Threading.AsyncLocal when built against .NET Standard.

If the accessor is not registered in the DI, then of course the context will not be saved anywhere. This is really important – and I have seen some questions already about that. If you just manually create an instance of HttpContextAccessor (which some people try), it will have no relationship to the HttpContextFactory or HttpContext, and the context will always be null. The accessor is merely a shortcut with a getter and setter, while all the logic of associating the HttpContext with the accessor instance is in HttpContextFactory.

And that’s basically how it works.

Injecting HttpContextAccessor

With all that set up, we could inject IHttpContextAccessor wherever we require access to the current instance of HttpContext. This of course means that your own components that rely on it, should be registered in/resolved from the IoC container too.

public class MyService
{
    private readonly IHttpContextAccessor _accessor; 

    public MyService(IHttpContextAccessor accessor)
    {
        _accessor = accessor;
    } 

    public void DoWork()
    {
        var context = _accessor.HttpContext;
        // continue with context instance
    }
}

Mimicking HttpContext.Current

One of the most infamous relicts of System.Web that is missing in ASP.NET Core is the static access to the current HttpContext.

I bet there is not a single ASP.NET developer, that, over the years, has not seen tons of programs, logic and extensions developed based on the magic and omnipresence of HttpContext.Current.

Now, trying to build your code around HttpContext.Current is really not a good idea, but I guess if you are migrating an enterprise type of app, with a lot of HttpContext.Current sprinkled around the business logic it may provide some temporary relief in terms of porting the application.

Our modern day HttpContext.Current would rely on resolving the context from IHttpContextAccessorand could look like this:

namespace System.Web
{
    public static class HttpContext
    {
        private static IHttpContextAccessor _contextAccessor; 

        public static Microsoft.AspNetCore.Http.HttpContext Current => _contextAccessor.HttpContext; 

        internal static void Configure(IHttpContextAccessor contextAccessor)
        {
            _contextAccessor = contextAccessor;
        }
    }
}

Notice, how we even placed it in System.Web namespace so that any potential migration you have is a bit easier.

We just need to add the code that will call into Configure as early as we can in the processing pipeline and pass in the IHttpContextAccessor. This can be achieved with two extension methods:

    public static class StaticHttpContextExtensions
    {
        public static void AddHttpContextAccessor(this IServiceCollection services)
        {
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        } 

        public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
        {
            var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
            System.Web.HttpContext.Configure(httpContextAccessor);
            return app;
        }
    }

The first one would be called from within ConfigureServices in your Startup and simply register the accessor in the DI. We have already established that this is necessary for the default IHttpContextFactory to share its instance of HttpContext correctly.

The second would be called from within Configure in your Startup, and it will make sure that our custom HttpContext.Current gets fed its IHttpContextAccessor so that it can work properly too.

And that’s it. Here is my Startup class which sets up the table for the static HttpContext.Current.

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHttpContextAccessor();
        } 

        public void Configure(IApplicationBuilder app)
        {
            app.UseStaticHttpContext();
            app.UseMvc();
        }
    }

And this is the rewritten example from above.

using System.Web; 

public class MyService
{
    public void DoWork()
    {
        var context = HttpContext.Current;
        // continue with context instance
    }
}

However, please think twice before going down that road.

ASP.NET Core Hosting :: In Proces Hosting ASP.NET Core Applications

$
0
0

We discussed about ASP.NET MVC Core 2.1 and discussed some internal details about its deployment on IIS as a reverse proxy (which is recommended), and also took a look on using Kestrel as an Edge Server. Although Kestrel is matured enough to be used as an Edge Server but still IIS is considered better option. We also saw, how ASP.NET Core requests are handled by IIS. We need to install the .NET Core Hosting bundle (download here) which adds a module named ASP.NET Core Module  (ANCM). ANCM is responsible to route the asp.net core request to Kestrel.

With ASP.NET Core 2.2, Microsoft introduced In-process hosting. This model allows us to host the asp.net core 2.2 directly inside the worker process (w3wp.exe) which is similar to earlier ASP.NET version. Let’s take a pictorial view

We can see that there is no dotnet.exe is involved here in the second part. All the components ANCM, CoreCLR and application code are loaded in same worker process.

To use the latest feature, we need to install the latest 2.2 bundle (download here) which installs the upgraded version of ANCM also referred as ANCMv2. After installation, both the modules can be seen in IIS modules section as

Why new version of ASP.NET Core Module (ANCMv2)?

Earlier the idea with ANCM to use IIS as a reverse proxy and leverage Kestrel as a backend web server (as it was not hardened enough as an edge server) but as Kestrel got all the required enhancements, MS reworked on ANCM so that IIS can be used another platform to host asp.net core applications without the need of Kestrel. ANCM got redesigned and divided in two components, a shim and a request handler.

     Shim – As the name suggests, it is a very light weight component which is continue to be installed as a global module via bundle which just work as an interface between IIS and request handler.

   Request Handler – Request Handler is now an independent component which does all the work and can be updated via nuget. We can have multiple versions of request handler side by side. It means we can have multiple application using its own request handler.

With earlier ANCM, it was available as global singleton module which is shared by all the application which is a major bottleneck in releasing newer versions as it has to support every application. With the new architecture, we also get better process management, performance enhancements and easy updates via nuget.

We have so many benefits with the new model however we have one limitation – one application pool can only host only one application (In ASP.NET Web Form/MVC we could share app pools with multiple applications) as we don’t have the concept of Application domains in CoreCLR and this feature supports to CoreCLR only.

Let’s see an example

Now I have created another sample web application application using ASP.NET Core 2.2 (used VS 2017 v15.9.4) and deployed to IIS after publishing that.

 

There is no brainer here, let’s see the processes

Just to compare with earlier version I am adding both here.

 

So we can see the difference, in first scenario (<ASP.NET Core 2.2) the application is running under dotnet.exe while in second scenario, it is running under the worker process (w3wp.exe) itself which boosts the performance significantly as we don’t have to manage the dotnet process (earlier approach could have reliability issues as well) and request doesn’t have to travel outside of the process.

ASP.NET Core 2.2 allows out of process deployment as well. When we publish our application, it generates a web.config which has following xml node

<aspNetCore processPath=”dotnet” arguments=”.\InProcApp.dll” stdoutLogEnabled=”false” stdoutLogFile=”.\logs\stdout” hostingModel=”InProcess” />

Here hosting model at the end defined as InProcess. We can change it to OutOfProcess which would be similar as earlier one and application would be running using dotnet.exe. These configuration can also be set via Visual Studio while debugging as

Go to Solution Explorer -> Right Click on project-> Debug (tab)-> Web Server settings section

Performance comparison

As mentioned above, with ASP.NET Core 2.2 allows us to host both the In-process and Out-of-process model (It is similar to earlier version). I have done sample load test using the Netling (know more about this tool here) and for out-of-process result is here

We can see that 2576 request got served per second. I changed the hosting as In-process and ran the same test again and the results are

Here we can see that request per second got increased significantly to 3742 which is approximate ~50% increase. Other data points like median, stddev also got reduced significantly. Itmay vary based on the scenario as I ran it on a developer VM and the application used was a default sample application using asp.net core 2.2 (not an empty application). However, Microsoft ran the test in performance labs where they got 4x throughput with In-process hosting.

 

Conclusion

Even kestrel was introduced with ASP.NET Core as a highly performant web server or as an alternate to IIS, it was always suggested to use IIS as frontend server in windows environment. Initially, many important features were missing in Kestrel which got added with the release of asp.net core 2.0 and 2.1, still IIS is advised to use for enterprise environment and internet facing application mainly due to security and stability reasons. There were several bottlenecks with having two different processes (w3wp.exe and dotnet.exe) and the way like port conflicts/not available, process management etc. All these can be avoided using In-process hosting model.

ASP.NET Core Hosting :: How to Setup Project in IOptionsSnapshot using ASP.NET and Reload Technique

$
0
0

In this article, I want to explore IOptionsSnapshot and show how to work with IOptionsSnapshot in ASP.NET Core 1.1.

We will use the dot-net CLI to create a new project and configure it using the reload technique in combination with IOptionsSnapshot.

Make sure you are using at least ASP.NET Core 1.1. Get started by creating a new folder that you want to work in, opening a console there and typing dotnet new mvc and dotnet restore to get the project in a starting position. Then open up a console and type code. to start Visual Studio Code on the current level.

You should now see all the files and folders of your project. We can now go ahead and create a typed class which represents the configuration we want to work with. In this case, this is just a file with a name property.

Config
  └── myConfig.json
  Controllers └── ...
  Views └── ...
  wwwroot └── ... ...
  Program.cs
  Startup.cs

myConfig.json

{
    "Person": {
        "Firstname": "John Doe"
    }
}

This leads us to the class

public class Person 
{
    public string Firstname { get; set; }
}

Config 
  └── myConfig.json 
  Controllers └── ... 
  Views └── ... 
  wwwroot └── ... ... 
  Program.cs 
  Startup.cs

which represents our configuration in our application.

We have to modify our constructor of the Startup.cs file a bit to load this new file:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddEnvironmentVariables();
    Configuration = builder.Build();
}

This then becomes: 

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddJsonFile($"config/myConfig.json", optional: false, reloadOnChange: true)
        .AddEnvironmentVariables();
    Configuration = builder.Build();
}

Pay attention to the realoadOnChange: true because that is what we are reaching out for.

So now that we loaded the file we need to add it to our configuration which is used in our app. Let's do this by adding the statement in the ConfigureServices -Method:

public void ConfigureServices(IServiceCollection services)
{
    // ...
    services.Configure<Person>(Configuration.GetSection("Person"));
}

Here we are mapping our values in JSON to a typed class called “Person.”

Now, this configuration is available through dependency injection and we can use it in our controllers!

public class HomeController : Controller 
{
    private readonly Person _person;
    public HomeController(IOptionsSnapshot<Person> person)
    {
        _person = person.Value;
    }
}

Pay attention to the “IOptionsSnapshot” we injected here which is different from the previous ASP.NET Core versions. Be sure to have the "Microsoft.Extensions.Options": "1.1.0" package installed and that you are using ASP.NET Core 1.1. We can now inject the IOptionsSnapshot<T> in our controller and use its value. For testing, we save the Firstname in the ViewData displaying it afterward.

namespace WebApplication6.Controllers
{
    public class HomeController : Controller
    {
        private readonly Person _person;
        public HomeController(IOptionsSnapshot<Person> person)
        {
            _person = person.Value;
        }
        public IActionResult Index()
        {
            ViewData["FirstName"] = _person.Firstname;
            return View();
        }
    }
}

Index.cshtml

<h3>@(ViewData["FirstName"])</h3>

If you now start the web application via dotnet run and you change the configuration without restarting the application, hit F5 to refresh the browser and you will see the new values.

ASP.NET Core 3.0 Hosting :: An Early Look at gRPC and ASP.NET Core 3.0

$
0
0

In this post, I want to introduce my very early experience (after a few hours of experimentation) of gRPC and ASP.NET Core 3.0. I’ve conducted some experiments as part of our quarterly Madgex hack day. This will be an introductory post so I don’t expect to show everything in fine detail. This is intended to give an overview of how the main pieces fit together and I’ll hopefully then dive into the details in future posts.

What is gRPC?

gRPC is a schema-first framework initially created by Google. It supports service to service communication over HTTP/2 connections. It uses the Protobuf wire transfer serialisation for lightweight, fast messaging between the services. As more and more of us build interconnected microservices it can sometimes be a pain using REST as our protocol over HTTP for such purposes. REST was designed for human-readable data transfer and often results in a fair amount of boiler-plate code on both the client and server services to implement.

gRPC allows us to define our message schema and “contract” up front using Protocol Buffers. This file is then used to automatically generate much of the client and server code on our behalf. It is an interesting technology and looks well placed to become a popular choice when working with microservices. For my hack day project, I wanted to take it for a quick spin and see if I could get a client and server working over gRPC.

NOTE: The information in this post is therefore based on early code and has the potential to change during the remaining previews and after release. If you’re reading this in the distant future you may want to look for updated blog posts from me!

Getting Started

Microsoft is actively contributing to the “gRPC for .NET” repository to support gRPC in the ASP.NET Core 3.0 timeframe. Currently, this is a work in progress, there is no formal NuGet package available and it depends on some features not yet available in the current ASP.NET Core 3.0 preview 2 release.

To support working with the newest bits, I found that I first needed to download the latest “preview 3 “daily build using the links provided on GitHub.

The sample “domain” for my hack was to develop a basic client data API which would be exposed as a gRPC server.

Creating the Protobuf Service Descriptor

gRPC uses a .proto (Protobuf) file to define the shape of your service contract. This contains the “schema” for the messages that will be sent between the exposed services.

My initial proto file looks like this:

syntax = "proto3";

package ClientPropertyEndpoint;

service ClientProperty {
    rpc GetProperty (PropertyRequest) returns (PropertyReply) {}
}

message PropertyRequest {
    string propertyId = 1;
}

message PropertyReply {
    string clientName = 1;
    string organisationName = 2;
    string productName = 3;
}

For now, I’ve defined a single RPC service interface called GetProperty. This accepts a PropertyRequest and returns a PropertyReply which are defined underneath the service.

Messages are defined using scalar types by providing the type, a name and then a unique number for the field. These uniquely identify the fields as they’ll appear in the binary message format and should not change once defined.

For example, my PropertyRequest message has a single string value called “propertyId” and I’ve assigned it a value of 1.

Creating the Server

The next step is to create an ASP.NET Core 3.0 server which will use code automatically generated from the proto file to reduce the amount of code we need to add. We can stub out the functionality over the generated code, which handles the serialisation and communication.

I created a standard ASP.NET Core 3.0 API project and then updated the csproj file in line with the available example in the grpc-dotnet repo.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <Protobuf Include="..\..\Proto\*.proto" GrpcServices="Server" />
    <Content Include="@(Protobuf)" LinkBase="" />
  </ItemGroup> 

  <ItemGroup>
    <PackageReference Include="Google.Protobuf" Version="3.6.1" />
    <PackageReference Include="Grpc.Tools" Version="1.19.0-pre1" PrivateAssets="All" />   

    <PackageReference Include="MediatR" Version="6.0.0" />
    <PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="6.0.1" />
  </ItemGroup>

</Project>

Without diving too deep this references the .proto file and the Grpc.Tools library in order to support the code generation work.

The next step is create a class derived from the generate code base class which once completed looks like this:

using Grpc.Core;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using ClientPropertyEndpoint;
using MediatR;

namespace Server
{
    public class PropertyService : ClientProperty.ClientPropertyBase
    {
        private readonly ILogger _logger;
        private readonly IMediator _mediator;

        public PropertyService(ILoggerFactory loggerFactory, IMediator mediator)
        {
            _logger = loggerFactory.CreateLogger<PropertyService>();
            _mediator = mediator;
        }

        public override async Task<PropertyReply> GetProperty(PropertyRequest request, ServerCallContext context)
        {
            _logger.LogInformation($"Handling request for property Id '{request.PropertyId}'");

            var property = await _mediator.Send(new ClientPropertyQuery(request.PropertyId));

            if (property is null)
                context.Status = new Status(StatusCode.NotFound, $"Property Id '{request.PropertyId}' was not found");

            return property ?? new PropertyReply();           
        }
    }
}

You can see the using statement in line 4 which matches the name of the package as defined in the proto file.

A static class ClientProperty has been generated which includes a sub-class called ClientPropertyBase which is what we derive from.

I can then override the base GetProperty method, which is so named because the proto file defines a service which includes that interface. It accepts a PropertyRequest type and returns a Task<PropertyReply>. Both of these have been code generated for me based on the proto file.

The only code I need to add here is the logic for fulfilling the request. In this sample, I have an in-memory store of some basic test data which I query using MediatR. It’s not too important how those bits work and you can code this however you need.

The program.cs for this API looks like this:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.ConfigureKestrel(options =>
                {
                    options.Limits.MinRequestBodyDataRate = null;
                    options.ListenLocalhost(50051, listenOptions =>
                    {
                        // later we'll use SSL
                        listenOptions.Protocols = HttpProtocols.Http2;
                    });
                })
            .UseStartup<Startup>();
            });
}

This using the new ASP.NET Core 3.0 generic host flow to register a web host which uses Kestrel. Kestrel is set up to listen on HTTP2 on port 50051.

The final bit I’ll show is the Startup class which looks like this:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<ClientPropertyStore>();

        services.AddGrpc();

        services.AddMediatR(typeof(Startup).GetTypeInfo().Assembly);
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting(routes =>
        {
            routes.MapGrpcService<PropertyService>();
        });
    }
}

This calls the AddGrpc extension on the IServiceCollection, available for now due to the Grpc.AspNetCore.Server code I copied in. Later this will be built in a NuGet library.

It then uses the new ASP.NET Core 3.0 routing middleware to map a GrpcService route to the PropertyService. This will allow the server to handle the gRPC requests.

Creating the Client

To send request to the server I created a basic .NET Core console app client. The csproj file for this also had a reference to the proto file so that the client code could be generated.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <LangVersion>latest</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <Protobuf Include="..\..\Proto\ClientProperty.proto" GrpcServices="Client" />
    <Content Include="@(Protobuf)" LinkBase="" />
  </ItemGroup> 

  <ItemGroup>
    <PackageReference Include="Google.Protobuf" Version="3.6.1" />
    <PackageReference Include="Grpc.Core" Version="1.19.0-pre1" />
    <PackageReference Include="Grpc.Tools" Version="1.19.0-pre1" PrivateAssets="All" />
  </ItemGroup>
</Project>

The only code needed lives in the Main method in this sample:

static async Task Main(string[] args)
{
    Console.WriteLine("Starting GRPC Client...");
    Console.WriteLine();

    var channel = new Channel("localhost:50051", SslCredentials.Insecure);
    var client = new ClientPropertyEndpoint.ClientProperty.ClientPropertyClient(channel);

    try
    {
        var response = await client.GetPropertyAsync(new PropertyRequest { PropertyId = "ac516792-94fc-4e0c-b39c-59b2fcd58a4e" });

        Console.WriteLine("Org Name: " + response.OrganisationName);
        Console.WriteLine("Client Name: " + response.ClientName);
        Console.WriteLine("Product Name: " + response.ProductName);
    }
    catch (RpcException ex)
    {
        if (ex.StatusCode == StatusCode.NotFound)
        {
            Console.WriteLine(ex.Status.Detail);
        }
    }

    Console.WriteLine();
    Console.WriteLine("Shutting down");
    channel.ShutdownAsync().Wait();

    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();
}

First we establish a gRPC channel to the server. For this sample I’m using insecure communication. I’ll show how SSL can be applied in a future post.

I then create a ClientPropertyClient which is a class created by the code gen process based on the proto file.

I can then call methods on the client which map to the methods as defined in the proto file. I simply create a PropertyRequest object (again, the class is from generated code) and send it via the client.

Here I write out the values from the PropertyResponse object to the console. Good enough for now!

I also handle a RpcException which is thrown if the server sends a NotFound status for example. I’ve not explored this too deeply so there may be better approaches to achieve this.

And that’s basically it. I can fire up the server and then fire the client up which will send a request over HTTP2 and gRPC. Awesome!

Summary

This has been a high-level overview of gRPC, after I’ve only spent a few hours learning how it works. I hope it serves to show one of the big benefits of the gRPC proto file which is the fact that we have to write very little boiler-plate code. There are no Controllers to define and even the models can be easily generated for both the client and server. On the client side, I don’t need to construct HTTP requests and fire them. I can simply make a call to a code generated client method, passing a simple request message.

ASP.NET Core Hosting :: How to Produce HTTP Response in ASP.NET Core Outside of MVC Controllers

$
0
0

ASP.NET Core 2.1 introduced support for a little (or, should I say, not at all) documented feature called IActionResultExecutor<T>. It allows us to use some of the action results -those that we are used to from MVC controllers – outside of the controller context, so for example from a middleware component.

Controller helper methods

The most important of the ActionResult family is the ObjectResult – which internally handles content negotiation – so determines what media type is suitable for the response, and serializes the response accordingly using the selected formatter (JSON, XML, Protobuf or whatever you support). The typical controller, using an ObjectResult might look like this:

[HttpGet("contacts")]
public IActionResult Get()
{
    var contacts = new[]
    {
        new Contact { Name = "Jervis", City = "Dallas" },
        new Contact { Name = "Not Jervis", City = "Not Dallas" }
    };
    // will do content negotiation
    return new ObjectResult(contacts);
}

We could also return a POCO directly from the action, but the framework would still end up using ObjectResult to process that, so ultimately it is still the same thing.

[HttpGet("contacts")]
public IEnumerable<Contact> Get()
{
    var contacts = new[]
    {
        new Contact { Name = "Jervis", City = "Dallas" },
        new Contact { Name = "Not Jervis", City = "Not Dallas" }
    };
    // will do content negotiation
    return contacts;
}

Finally, and this is what this post is about, you could replace our usage of ObjectResult, or the POCO, with a call to Ok() on the base controller:

[HttpGet("contacts")]
public IActionResult Get()
{
    var contacts = new[]
    {
        new Contact { Name = "Jervis", City = "Dallas" },
        new Contact { Name = "Not Jervis", City = "Not Dallas" }
    };
    // will do content negotiation
    return Ok(contacts);
}

This is really still the same as before, because Ok() actually uses ObjectResult under the hood, it’s just expressed in a slightly different way. Now, if you have done any work with MVC controllers, I am sure you are used to those helper methods that are there on the the framework’s ControllerBase, like our Ok() or other – for example Unauthorized() or File(), to name just two of them.

They come in many, many variants (the base controller is 2700+ lines of code…), and are used as shortcuts into the many ActionResults that the framework offers. You can find a full list here. From my experience with various ASP.NET Core MVC projects, I would say that these helper methods are extremely popular among developers – they make the code very concise. They also hide certain complexity level of dealing with producing the HTTP responses, yet still make it very obvious to understand what is going on.

Controller feeling, without a controller

What we recently introduced into WebApiContrib.Core is a similar set of methods as found on the base controller, but ported as extension methods on top of HttpContext. This is done as a combination of IActionResultExecutor<T> features and “manual” response creation. Meaning we either mimic the behavior of the method from base controller by manually crafting the HTTP response, setting headers, status codes and so on, or we really reach into the IActionResultExecutor<T> infrastructure and invoke the relevant action result from the MVC framework.

The end result is very neat, and you get very similar helper method set that you can now enjoy from your non-controller code – primarily middleware but potentially some other places too.

So imagine you are creating a “lightweight” HTTP endpoint using the new Endpoint Routing feature. You can now use the new helper methods to produce the response. Here is a full sample application setup:

public static async Task Main(string[] args) =>
    await WebHost.CreateDefaultBuilder(args)
        .ConfigureServices(s =>
        {
            s.AddRouting();            

            // necessary to wire in ActionResults
            // and content negotiation
            // you can manually register other formatters here
            // for example Messagepack or Protobuf
            s.AddMvc(); 

            // note: due to the current state of ASP.NET Core 3.0 (preview3)
            // you need to manually call: s.AddMvc().AddNewtonsoftJson()
            // to use JSON formatter. This will be fixed in the future in the framework
        })
        .Configure(app =>
        {
            app.UseRouting(r =>
            {
                r.MapGet("contacts", async context =>
                {
                    var contacts = new[]
                    {
                        new Contact { Name = "Jervis", City = "Dallas" },
                        new Contact { Name = "No Jervis", City = "Not Dallas" }
                    }; 

                    // from WebApiContrib.Core
                    // will do content negotiation
                    await context.Ok(contacts);
                });
            });
        }).Build().RunAsync();

In order to make this work, the only thing that is needed, is that it’s necessary to have a call to services.AddMvc() in the DI container setup, as the action result and the executor infrastructure is bootstrapped there.

Other than that, this Ok() extension method on HttpContext will behave exactly the same as the Ok() on base controller – including performing the full content negotiation. The example uses endpoint routing from ASP.NET Core 3.0, but it would work from any place in ASP.NET Core request processing pipeline, for example with an IRouter in ASP.NET Core 2.1 or any middleware.

Another example we could quickly look at here, is returning a file stream – instead of dealing with it manually, including all the complexity of async reading of the stream or stuff related to Content-Disposition headers and so on, we can simply use an extension method now:

app.UseRouting(r =>
{
    r.MapGet("download", async context =>
    {
        // some file path
        var path = Path.GetFullPath(Path.Combine("files", "myfile.pdf")); 

        // from WebApiContrib.Core
        await context.PhysicalFile(path, "application/pdf");
    });
});

In this particular case, the helper method would end up using an action result, a PhysicalFileActionResult, which will take care of reading the file in a non-blocking way and make sure all HTTP response details are correctly handled. And just like before, PhysicalFile() mimics a corresponding method from the MVC base controller.

The full list of the available extension methods can be found below. And I really encourage you to try them – they are part of WebApiContrib.Core 2.2.0.

Task Accepted(this HttpContext c, Uri uri, object value);
Task Accepted(this HttpContext c, string uri, object value);
Task Accepted(this HttpContext c, string uri);
Task Accepted(this HttpContext c, Uri uri);
Task Accepted(this HttpContext c, object value);
Task Accepted(this HttpContext c);
Task BadRequest(this HttpContext c);
Task BadRequest(this HttpContext c, object error);
Task BadRequest(this HttpContext c, ModelStateDictionary modelState);
Task Conflict(this HttpContext c, object error);
Task Conflict(this HttpContext c, ModelStateDictionary modelState);
Task Conflict(this HttpContext c);
Task Content(this HttpContext c, string content, MediaTypeHeaderValue contentType);
Task Content(this HttpContext c, string content, string contentType, Encoding contentEncoding);
Task Content(this HttpContext c, string content, string contentType);
Task Content(this HttpContext c, string content);
Task Created(this HttpContext c, string uri, object value);
Task Created(this HttpContext c, Uri uri, object value);
Task File(this HttpContext c, string virtualPath, string contentType);
Task File(this HttpContext c, Stream fileStream, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
Task File(this HttpContext c, Stream fileStream, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
Task File(this HttpContext c, Stream fileStream, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
Task File(this HttpContext c, string virtualPath, string contentType, string fileDownloadName);
Task File(this HttpContext c, string virtualPath, string contentType, string fileDownloadName, bool enableRangeProcessing);
Task File(this HttpContext c, string virtualPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
Task File(this HttpContext c, string virtualPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
Task File(this HttpContext c, Stream fileStream, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
Task File(this HttpContext c, string virtualPath, string contentType, bool enableRangeProcessing);
Task File(this HttpContext c, Stream fileStream, string contentType, string fileDownloadName, bool enableRangeProcessing);
Task File(this HttpContext c, byte[] fileContents, string contentType, string fileDownloadName);
Task File(this HttpContext c, Stream fileStream, string contentType, bool enableRangeProcessing);
Task File(this HttpContext c, Stream fileStream, string contentType);
Task File(this HttpContext c, byte[] fileContents, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
Task File(this HttpContext c, byte[] fileContents, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
Task File(this HttpContext c, byte[] fileContents, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
Task File(this HttpContext c, byte[] fileContents, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
Task File(this HttpContext c, byte[] fileContents, string contentType, string fileDownloadName, bool enableRangeProcessing);
Task File(this HttpContext c, string virtualPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
Task File(this HttpContext c, byte[] fileContents, string contentType, bool enableRangeProcessing);
Task File(this HttpContext c, byte[] fileContents, string contentType);
Task File(this HttpContext c, Stream fileStream, string contentType, string fileDownloadName);
Task File(this HttpContext c, string virtualPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
Task Forbid(this HttpContext c);
Task LocalRedirect(this HttpContext c, string localUrl);
Task LocalRedirectPermanent(this HttpContext c, string localUrl);
Task LocalRedirectPermanentPreserveMethod(this HttpContext c, string localUrl);
Task LocalRedirectPreserveMethod(this HttpContext c, string localUrl);
Task NoContent(this HttpContext c);
Task NotFound(this HttpContext c, object value);
Task NotFound(this HttpContext c);
Task Ok(this HttpContext c);
Task Ok(this HttpContext c, object value);
Task PhysicalFile(this HttpContext c, string physicalPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
Task PhysicalFile(this HttpContext c, string physicalPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
Task PhysicalFile(this HttpContext c, string physicalPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing);
Task PhysicalFile(this HttpContext c, string physicalPath, string contentType);
Task PhysicalFile(this HttpContext c, string physicalPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag);
Task PhysicalFile(this HttpContext c, string physicalPath, string contentType, string fileDownloadName, bool enableRangeProcessing);
Task PhysicalFile(this HttpContext c, string physicalPath, string contentType, string fileDownloadName);
Task PhysicalFile(this HttpContext c, string physicalPath, string contentType, bool enableRangeProcessing);
Task Redirect(this HttpContext c, string url);
Task RedirectPermanent(this HttpContext c, string url);
Task RedirectPermanentPreserveMethod(this HttpContext c, string url);
Task RedirectPreserveMethod(this HttpContext c, string url);
Task StatusCode(this HttpContext c, int statusCode);
Task StatusCode(this HttpContext c, int statusCode, object value);
Task Unauthorized(this HttpContext c);
Task Unauthorized(this HttpContext c, object value);
Task UnprocessableEntity(this HttpContext c, object error);
Task UnprocessableEntity(this HttpContext c, ModelStateDictionary modelState);
Task UnprocessableEntity(this HttpContext c);
Task ValidationProblem(this HttpContext c, ValidationProblemDetails descriptor);
Task ValidationProblem(this HttpContext c, ModelStateDictionary modelStateDictionary);
Task WriteActionResult<TResult>(this HttpContext c, TResult result) where TResult : IActionResult;

Viewing all 427 articles
Browse latest View live