All About ASP.NET and ASP.NET Core 2 Hosting BLOG

Tutorial and Articles about ASP.NET and the latest ASP.NET Core

ASP.NET Core Hosting :: How to Handle Multipart Request with JSON and File Uploads in ASP.NET Core

clock May 15, 2019 09:29 by author Jervis

Suppose we’re writing an API for a blog. Our "create post" endpoint should receive the title, body, tags and an image to display at the top of the post. This raises a question: how do we send the image? There are at least 3 options:

Embed the image bytes as base64 in the JSON payload, e.g.

{
    "title": "My first blog post",
    "body": "This is going to be the best blog EVER!!!!",
    "tags": [ "first post", "hello" ],
    "image": "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
}

This works fine, but it’s probably not a very good idea to embed an arbitrarily long blob in JSON, because it could use a lot of memory if the image is very large.

Send the JSON and image as separate requests. Easy, but what if we want the image to be mandatory? There’s no guarantee that the client will send the image in a second request, so our post object will be in an invalid state.

Send the JSON and image as a multipart request.

The last approach seems the most appropriate; unfortunately it’s also the most difficult to support… There is no built-in support for this scenario in ASP.NET Core. There is some support for the multipart/form-data content type, though; for instance, we can bind a model to a multipart request body, like this:

public class MyRequestModel
{
    [Required]
    public string Title { get; set; }
    [Required]
    public string Body { get; set; }
    [Required]
    public IFormFile Image { get; set; }


public IActionResult Post([FromForm] MyRequestModel request)
{
    ...
}

But if we do this, it means that each property maps to a different part of the request; we’re completely giving up on JSON.

There’s also a MultipartReader class that we can use to manually decode the request, but it means we have to give up model binding and automatic model validation entirely.

Custom model binder

Ideally, we’d like to have a request model like this:

public class CreatePostRequestModel
{
    [Required]
    public string Title { get; set; }
    [Required]
    public string Body { get; set; }
    public string[] Tags { get; set; }
    [Required]
    public IFormFile Image { get; set; }
}

Where the TitleBody and Tags properties come from a form field containing JSON and the Image property comes from the uploaded file. In other words, the request would look like this:

POST /api/blog/post HTTP/1.1
Content-Type: multipart/form-data; boundary=AaB03x  

--AaB03x
Content-Disposition: form-data; name="json"
Content-Type: application/json  

{
    "title": "My first blog post",
    "body": "This is going to be the best blog EVER!!!!",
    "tags": [ "first post", "hello" ]
}
--AaB03x
Content-Disposition: form-data; name="image"; filename="image.jpg"
Content-Type: image/jpeg  

(... content of the image.jpg file ...)
--AaB03x

Fortunately, ASP.NET Core is very flexible, and we can actually make this work, by writing a custom model binder.

Here it is:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json; 

namespace TestMultipart.ModelBinding
{
    public class JsonWithFilesFormDataModelBinder : IModelBinder
    {
        private readonly IOptions<MvcJsonOptions> _jsonOptions;
        private readonly FormFileModelBinder _formFileModelBinder; 

        public JsonWithFilesFormDataModelBinder(IOptions<MvcJsonOptions> jsonOptions, ILoggerFactory loggerFactory)
        {
            _jsonOptions = jsonOptions;
            _formFileModelBinder = new FormFileModelBinder(loggerFactory);
        } 

        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext)); 

            // Retrieve the form part containing the JSON
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.FieldName);
            if (valueResult == ValueProviderResult.None)
            {
                // The JSON was not found
                var message = bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(bindingContext.FieldName);
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, message);
                return;
            } 

            var rawValue = valueResult.FirstValue; 

            // Deserialize the JSON
            var model = JsonConvert.DeserializeObject(rawValue, bindingContext.ModelType, _jsonOptions.Value.SerializerSettings); 

            // Now, bind each of the IFormFile properties from the other form parts
            foreach (var property in bindingContext.ModelMetadata.Properties)
            {
                if (property.ModelType != typeof(IFormFile))
                    continue; 

                var fieldName = property.BinderModelName ?? property.PropertyName;
                var modelName = fieldName;
                var propertyModel = property.PropertyGetter(bindingContext.Model);
                ModelBindingResult propertyResult;
                using (bindingContext.EnterNestedScope(property, fieldName, modelName, propertyModel))
                {
                    await _formFileModelBinder.BindModelAsync(bindingContext);
                    propertyResult = bindingContext.Result;
                } 

                if (propertyResult.IsModelSet)
                {
                    // The IFormFile was sucessfully bound, assign it to the corresponding property of the model
                    property.PropertySetter(model, propertyResult.Model);
                }
                else if (property.IsBindingRequired)
                {
                    var message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName);
                    bindingContext.ModelState.TryAddModelError(modelName, message);
                }
            } 

            // Set the successfully constructed model as the result of the model binding
            bindingContext.Result = ModelBindingResult.Success(model);
        }


    }
}

To use it, just apply this attribute to the CreatePostRequestModel class above:

[ModelBinder(typeof(JsonWithFilesFormDataModelBinder), Name = "json")]}
public class CreatePostRequestModel

This tells ASP.NET Core to use our custom model binder to bind this class. The Name = "json" part tells our binder from which field of the multipart request it should read the JSON (this is the bindingContext.FieldName in the binder code).

Now we just need to pass a CreatePostRequestModel to our controller action, and we’re done:

[HttpPost]
public ActionResult<Post> CreatePost(CreatePostRequestModel post)
{
    ...
}

This approach enables us to have a clean controller code and keep the benefits of model binding and validation. It messes up the Swagger/OpenAPI model though, but hey, you can’t have everything!



ASP.NET Core Hosting :: How to Create CRUD App Using Blazor and ASP.NET Core

clock April 12, 2019 07:43 by author Jervis

Blazor is an experimental .NET web framework using C#/Razor and HTML that runs in the browser via WebAssembly. It simplifies the process of creating single page application (SPA) and at the same time also brings the power of .NET on the table. It runs in the browser on a real .NET runtime (Mono) implemented in WebAssembly that executes normal .NET assemblies. In this post, we’ll see how to set up blazor and create a CRUD app using blazor and ASP.NET Core.

Creating a Blazor App

To create a blazor app, open Visual Studio 2017 “Preview” version, hit Ctrl+Shift+N and select the ASP.NET Core Web Application (.NET Core) project type from the templates. When you click Ok, you will get the following prompt,

If you don’t see these blazor templates, make sure .NET Core and ASP.NET Core 2.0 are selected at the top. As you can see, there are 2 blazor templates. The standalone “Blazor” template will create a static blazor app and “Blazor (ASP.NET Core Hosted)” will create an ASP.NET Core hosted blazor app. Choose “Blazor (ASP.NET Core Hosted)” to create the blazor app. Now, our first Blazor app will be created. In the solution explorer, you will find 3 projects created.

  • <Project Name>.Client: Standard blazor application.
  • <Project Name>.Server: It’s an ASP.NET Core Web API project.
  • <Project Name>.Shared: It’s a .NET standard class library project used for holding the shared resources.

You should run the app to make sure that there are no errors. Press Ctrl-F5 to run the app without the debugger. Running with the debugger (F5) is not supported at this time. Next thing is to extend this app to create a CRUD app.

Create the CRUD App

Before we move on, take a look at the following image to get an idea of what we are building.

As you can see, we are building a ToDo List app supporting all the CRUD operations and a listing of the ToDo items. We’ll use Entity Framework Core in-memory provider to store the ToDo list. So let’s begin.

First, create a ToDoList class in the Shared project with the following code. It’s a simple class with only two members.

public class ToDoList
{
    public int ID { get; set; }

    public string Item { get; set; }
}

Next, create EF DBContext to interact with the database. To do that, create a new folder named “Data” in the Server project. Add a new class file named ToDoListContext with the following code.

public class ToDoListContext : DbContext
{
    public ToDoListContext(DbContextOptions<ToDoListContext> options) : base(options) { }

    public DbSet<ToDoList> ToDoLists { get; set; }
}

We’ll need to configure InMemory db provider. To do that, Open Startup.cs class and navigate to the ConfigureServices method to configure it (Line no. 4).

public void ConfigureServices(IServiceCollection services)
{
    // Use Entity Framework in-memory provider for this sample
    services.AddDbContext<ToDoListContext>(options => options.UseInMemoryDatabase("ToDoList"));

    services.AddMvc().AddJsonOptions(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

    services.AddResponseCompression(options =>
    {
        options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
        {
            MediaTypeNames.Application.Octet,
            WasmMediaTypeNames.Application.Wasm,
        });
    });
}

Next, we’ll need an API controller for all CRUD operations. To do that, create a new controller named ToDoListController inside the Controller folder in the Server project with the following code.

[Produces("application/json")]
[Route("api/ToDo")]
public class ToDoListController : Controller
{
    private readonly ToDoListContext _context;

    public ToDoListController(ToDoListContext context)
    {
        _context = context;
    }

    // GET: api/ToDo
    [HttpGet]
    public IEnumerable<ToDoList> GetToDo()
    {
        return _context.ToDoLists;
    }

    // POST: api/ToDo
    [HttpPost]
    public async Task<IActionResult> PostToDo([FromBody] ToDoList todo)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        _context.ToDoLists.Add(todo);
        await _context.SaveChangesAsync();
        return CreatedAtAction("GetToDo", new { id = todo.ID }, todo);
    }

    // PUT: api/ToDo/5
    [HttpPut("{id}")]
    public async Task<IActionResult> PutToDo([FromRoute] int id, [FromBody] ToDoList todo)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        if (id != todo.ID)
            return BadRequest();

        _context.Entry(todo).State = EntityState.Modified;
        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ToDoExists(id))
                return NotFound();
            else
                throw;
        }
        return NoContent();
    }

    // DELETE: api/ToDo/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteToDo([FromRoute] int id)
    {
        var ToDo = await _context.ToDoLists.SingleOrDefaultAsync(m => m.ID == id);
        if (ToDo == null)
            return NotFound();

        _context.ToDoLists.Remove(ToDo);
        await _context.SaveChangesAsync();
        return Ok(ToDo);
    }

    private bool ToDoExists(int id)
    {
        return _context.ToDoLists.Any(e => e.ID == id);
    }
}

Here, the controller has API for all CRUD operations with proper validations. Quite familiar piece of code, isn’t it?

Blazor App Code

Next, we need to add the ToDo component to the Client App. The default app is already having Home, Counter and Fetch Data component. To add ToDo component, right-click on Pages folder and select Add > New Item. Select Web from the left panel, then select “Razor View” from templates panel and name it ToDo.cshtml. Put the following code in the file.

@page "/todo"
@using ASPNETBlazorCRUDApp.Shared
@using Microsoft.AspNetCore.Blazor.Browser.Interop
@inject HttpClient Http

<h1>ToDo List</h1>

<div>
    <div class="row">
        <div class="col-sm-1">
            <p>Item:</p>
        </div>
        <div class="col-sm-4">
            <input id="todoName" placeholder="Item Name" @bind(itemName)>
        </div>
    </div>
    <br />
    <div class="row">
        <div class="col-sm-1">
            <button class="btn btn-info" id="btnAdd" @onclick(async () => await AddToDo())>Add</button>
        </div>
        <div class="col-sm-2">
            @if (todos != null && todos.Count > 0)
            {
                <button class="btn btn-danger" @onclick(async () => await DeleteAllToDos())>Delete All</button>
            }
        </div>
    </div>
</div>
<br /><br />
@if (todos == null)
{
    <p><em>Loading...</em></p>
}
else
{
    @if (todos.Count > 0)
    {
        <table class='table table-striped table-bordered table-hover table-condensed' style="width:80%;">
            <thead>
                <tr>
                    <th style="width: 40%">Name</th>
                    <th style="width: 40%">Edit</th>
                    <th style="width: 20%">Delete</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var todo in todos)
                {
                    <tr>
                        <td>
                            <span id="spn_@todo.ID">@todo.Item</span>
                            <input id="txt_@todo.ID" @bind(UpdateItemName) style="display:none;">
                        </td>
                        <td>
                            <button id="btnEdit_@todo.ID" class="btn btn-primary" @onclick(() => EditToDo(todo.ID, todo.Item))>Edit</button>
                            <button id="btnUpdate_@todo.ID" style="display:none;" class="btn btn-success" @onclick(async () => await UpdateToDo(todo.ID))>Update</button>
                            <button id="btnCancel_@todo.ID" style="display:none;" class="btn btn-primary" @onclick(() => CancelToDo(todo.ID))>Cancel</button>
                        </td>
                        <td><button class="btn btn-danger" @onclick(async () => await DeleteToDo(todo.ID))>Delete</button></td>
                    </tr>
                }
            </tbody>
        </table>
    }
}

<script>
    Blazor.registerFunction('ShowControl', (id, item, bShow) => {
        if (bShow) {
            var txtInput = document.getElementById("txt_" + id);
            document.getElementById("spn_" + id).style.display = "none";
            txtInput.style.display = "";
            txtInput.value = item;
            txtInput.focus();
            document.getElementById("btnEdit_" + id).style.display = "none";
            document.getElementById("btnUpdate_" + id).style.display = "";
            document.getElementById("btnCancel_" + id).style.display = "";
        }
        else {
            document.getElementById("spn_" + id).style.display = "";
            document.getElementById("txt_" + id).style.display = "none";
            document.getElementById("btnEdit_" + id).style.display = "";
            document.getElementById("btnUpdate_" + id).style.display = "none";
            document.getElementById("btnCancel_" + id).style.display = "none";
        }
        return true;
    });
</script>
@functions {
        string itemName;
        string UpdateItemName;

        IList<ToDoList> todos = new List<ToDoList>();

protected override async Task OnInitAsync()
    {
        await Refresh();
    }

    private async Task Refresh()
    {
        todos = await Http.GetJsonAsync<ToDoList[]>("/api/ToDo");
        StateHasChanged();
    }

    private async Task AddToDo()
    {
        if (!string.IsNullOrEmpty(itemName))
        {
            await Http.SendJsonAsync(HttpMethod.Post, "/api/ToDo", new ToDoList
            {
                Item = itemName,
            });

            itemName = "";
            await Refresh();
        }
    }

    private async Task UpdateToDo(int id)
    {
        if (!string.IsNullOrEmpty(UpdateItemName))
        {
           await Http.SendJsonAsync(HttpMethod.Put, $"/api/ToDo/{id}", new ToDoList
            {
                ID = id,
                Item = UpdateItemName,
            });

            await Refresh();
            //UpdateItemName = "";

            RegisteredFunction.Invoke<bool>("ShowControl", id.ToString(), "", false);
        }
    }

    private async Task DeleteToDo(int id)
    {
        await Http.DeleteAsync($"/api/ToDo/{id}");
        await Refresh();
    }

    private void EditToDo(int id, string itemName)
    {
        RegisteredFunction.Invoke<bool>("ShowControl", id.ToString(), itemName, true);
    }

    private void CancelToDo(int id)
    {
        RegisteredFunction.Invoke<bool>("ShowControl", id.ToString(), "", false);
    }

    private async Task DeleteAllToDos()
    {
        foreach (var c in todos)
        {
            await Http.DeleteAsync($"/api/ToDo/{c.ID}");
        }

        await Refresh();
    }
}

Let’s understand this code. The above code can be divided into 3 sections (HTML, JavaScript and C#). We’ll take a look at each of them in details. before, we do that, let’s understand the very first 4 lines.

@page "/todo"
@using ASPNETBlazorCRUDApp.Shared
@using Microsoft.AspNetCore.Blazor.Browser.Interop
@inject HttpClient Http

  • We are defining the route for this page using @page directive. So appending “/todo” to base URL will redirect to this component.
  • Including the ASPNETBlazorCRUDApp.Shared namespace as ToDoList class is used.
  • The namespace Microsoft.AspNetCore.Blazor.Browser.Interop is included to call JavaScript from the Blazor code. Currently, WebAssembly and therefore Mono and Blazor have no direct access to the browser’s DOM API. Read this post for a detailed information.
  • We are also injecting HTTPClient dependency to call the server-side API.

Now,let’s understand the each section.

HTML

The HTML part is quite simple if you are familiar with Razor syntax. It has a table and a couple of buttons. The @bind is used for two-way data-binding. Read more about data binding here. The @onclick is used to call the method on the click of the button.

JavaScript

Blazor directly can’t call JavaScript function. From learn-blazor.com

To call other JS libraries or your own custom JS/TS code from .NET, the current approach is to register a named function in a JavaScript/TypeScript file, e.g.:

// This is JavaScript
Blazor.registerFunction('doPrompt', message => {
  return prompt(message);
});

… and then wrap it for calls from .NET:

// This is C#
public static bool DoPrompt(string message)
{
    return RegisteredFunction.Invoke<bool>("doPrompt", message);
} 

The JavaScript function named ShowControl defined in the code, controls the visibility of the HTML elements. This is called from C# code on click of Edit, Update and Cancel button.

C#

At the bottom of the page, there is a @functions section which contains code for making server-side web api call for CRUD operations, calling JavaScript and refreshing the ToDo list. The only new thing here is the way C# makes a call to JavaScript ShowControl function on Edit, Update and Cancel button. Other than that it’s simple and familiar code.

Lastly, we need to add the “ToDo” component link in the navigation bar. To do that, open the NavMenu.html file located inside the Shared folder in the client app and add the following code just after the “Fetch Data” link.

<li>
    <NavLink href="/todo">
        <span class='glyphicon glyphicon-list-alt'></span> To Do
    </NavLink>
</li>

That’s it. Run the application and you should see the following.

 

Final Thoughts

These are still early days for Blazor, but we can start building component-based web apps that run in the browser with .NET. Initially, you would find difficult to make progress. Microsoft has promised to bring many new features and improvements planned for future updates. Let’s hope that soon there will be an official documentation and great community support. In this post, we learned about the new .NET framework – Blazor and also created a simple CRUD application using Blazor.

I am really excited to play with this, so more blog post coming up on Blazor. Thank you for reading. Keep visiting this blog and share this in your network. Please put your thoughts and feedback in the comments section.



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

clock March 26, 2019 13:05 by author Jervis

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;



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

clock March 22, 2019 09:36 by author Jervis

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 Setup Project in IOptionsSnapshot using ASP.NET and Reload Technique

clock March 19, 2019 09:49 by author Jervis

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 Hosting :: In Proces Hosting ASP.NET Core Applications

clock March 15, 2019 08:18 by author Jervis

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 Access HttpContext Outside of Framework Components in ASP.NET Core

clock March 13, 2019 08:44 by author Jervis

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 MVC Hosting :: Dependency Injection Into Actions in ASP.NET Core MVC 2.1

clock March 4, 2019 10:15 by author Jervis

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 3 Hosting :: ASP.NET Core 3 Preview

clock February 26, 2019 06:50 by author Jervis

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 Hosting :: How to Send and Receive Email in ASP.NET Core Using Mailkit

clock February 18, 2019 07:36 by author Jervis

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!



Cheap ASP.NET 4.5 Hosting

We’re a company that works differently to most. Value is what we output and help our customers achieve, not how much money we put in the bank. It’s not because we are altruistic. It’s based on an even simpler principle. "Do good things, and good things will come to you".

Success for us is something that is continually experienced, not something that is reached. For us it is all about the experience – more than the journey. Life is a continual experience. We see the Internet as being an incredible amplifier to the experience of life for all of us. It can help humanity come together to explode in knowledge exploration and discussion. It is continual enlightenment of new ideas, experiences, and passions


Author Link

 photo ahp banner aspnet-01_zps87l92lcl.png

 

Corporate Address (Location)

ASPHostPortal
170 W 56th Street, Suite 121
New York, NY 10019
United States

Tag cloud

Sign in