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 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 Hosting :: How to Set Headers and HTTP Status Codes in ASP.NET Core

clock February 7, 2019 11:36 by author Jervis

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 Implement Action Filters in ASP.NET Core

clock January 28, 2019 08:50 by author Jervis

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 1.0 Hosting - ASPHostPortal :: Publish Your First ASP.NET Core Project

clock October 7, 2016 20:37 by author Jervis

Here are simple tutorial how to build your ASP.NET Core application. It’s just simple steps and you can follow it easily.

Install .NET Core First

First, please make sure you install .NET Core SDK for Windows

With that installed, it’s time to build your first application.

Open up a command prompt (or use the in-built terminal in Visual Studio Code) and start by creating a folder for your application, then initialising it.

mkdir CoreApp
cd CoreApp
dotnet new

When you run the dotnet command for the first time you’ll see some information about how .NET Core collects usage data and initially populates a local package cache. Once you’ve seen this message you won’t see it again on the same machine.

Project.json and Program.cs File

One of the most striking things about getting started with .NET Core is that you don’t end up with lots of files and dependencies right out of the gate, just the minimum you need for an empty web site.

In fact, all you’ll be left with is a project.json and Program.cs file.

At this point, this is just a .net Core app (not web) which prints “Hello World” to the console.

If you take a look at project.json you’ll see the minimum dependencies your new .net core app needs to run.

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0"
        }
      },
      "imports": "dnxcore50"
    }
  }
}

When you create a new .net core application like this, it’s dependencies are not downloaded automatically. To do that, you simply need to issue a new command to restore the dependencies and then to run the app.

dotnet restore
dotnet run

Launch the Application

So your app just compiled and launched. It looks suspiciously like a console application, because it is a console application.

Up until now, everything you’ve done has resulted in a minimal .net core console application.

So how do you turn it into a web site?

Well you need to update project.json to tell it to add the Kestrel HTTP server as a dependency.

Kestrel is a lightning fast cross-platform web server which can be used to self-host your web application. In other words, you can tell your new web app that Kestrel is a dependency and then run your site on it without relying on IIS or IIS Express.

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0"
        },
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0"
      },
      "imports": "dnxcore50"
    }
  }
}

You’ve added a dependency so now you need to download that dependency using the restore command.

dotnet restore

Incidentally, in case you’re wondering where donet restore is restoring packages to, the default location is %userprofile%\.nuget\packages

Next up, you’ll need to create a Startup.cs file. This will define how incoming web requests should be handled.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; 

namespace ConsoleApplication {
    public class Startup{
        public void Configure(IApplicationBuilder app){
            app.Run(context => {
                return context.Response.WriteAsync("Hello world");
            });
        }
    }
}

This is about as simple as it comes, you simply tell your app to always return a response and write the text “Hello world” to it (for any request to your web application).

At this point, you haven’t told your app to start Kestrel (to start accepting web requests). You can do that by updating Program.cs.

using System;
using Microsoft.AspNetCore.Hosting; 

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello World!"); 

            var host = new WebHostBuilder()
            .UseKestrel()
            .UseStartup<Startup>()
            .Build(); 

            host.Run();
        }
    }
}

Should you wish, you can happily delete Console.WriteLine("Hello World!") as you’ve replaced it with something far more useful, you’ve told Core to launch Kestrel using the Startup class you just created.

Go ahead and run your app.

dotnet run

You’ll see a message telling you that your app is up and running and where you can access it.

Hosting environment: Development
Content root path: C:\Users\Jervis\CoreApp\bin\Debug\netcoreapp1.0
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Hit http://localhost:5000 in a browser!

 



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