6. Current status
■ ASP.NET 5 has been renamed to ASP.NET Core 1.0
■ May 16, 2016 - Announcing ASP.NET Core RC2
■ https://docs.asp.net/en/latest/
■ https://blogs.msdn.microsoft.com/webdev/
7. Runtime platforms
■ Classical .Net Framework.As always, it can be run on windows.
■ .Net Core.This is cross-platform environment officially developed and supported by
Microsoft.Can be installed on windows, linux and Mac.
■ Mono.This is open-source cross-platform port of .NET Framework for non-windows
systems. It is not officially supported by Microsoft and probably slower than .Net Core.
8. Web application
■ No more XML configuration, configuration now in JSON
■ Project.json as common project definition file
■ Startup.cs as entry point of application
■ Microsoft.AspNet.Server.Kestrel as running web server
■ All usings are Nuget packages
■ No more required csproj file, all files will be included in build
■ Web application = self-hostable console-application
12. Startup.cs
public class Startup
{
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder().AddJsonFile("Configuration/AppSettings.json").AddEnvironmentVariables();
this.Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set; }
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseStaticFiles();
app.UseMvc();
}
}
Configuration loading
Services, filters, options, dependency injection, etc
Logging, middleware, routing
13. Configuration loading
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("Configuration/AppSettings.json")
.AddJsonFile("Configuration/AmqpLoggingSettings.json")
.AddEnvironmentVariables();
this.Configuration = builder.Build();
this.Configuration["WebRootPath"] = env.WebRootPath;
this.Configuration["AppRootPath"] = appEnv.ApplicationBasePath;
}
RC1
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
RC2
14. Services, filters, options, dependency injection…
// This method gets called by the runtime. Use this method to add services to the
container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(
mvcOptions =>
{
mvcOptions.Filters.Add(typeof(GlobalExceptionInterseptor));
mvcOptions.Filters.Add(typeof(JsonWebTokenAuthentification));
});
ConfigureOptions(services);
ConfigureDependencyInjection(services);
}
15. Request filter
public class JsonWebTokenAuthentification : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// if AllowAnonymous attribute is present - skip other checks
if (context.Filters.OfType<AllowAnonymousFilter>().Any())
{
await next();
return;
}
else
{
context.Result = new HttpUnauthorizedResult();
return;
}
}
16. Options model – load configuration
https://docs.asp.net/en/latest/fundamentals/configuration.html#using-options-and-configuration-objects
{
"AmqpLoggerConfiguration": {
"ServerAddress": "http://localhost:15672",
"UserName": "guest",
"Password": "guest",
"VirtualHost": "%2f",
"ExchangeName": "gelf.fanout",
"Facility": “MyApplication"
}
} AmqpLoggingSettings.json
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("Configuration/AppSettings.json")
.AddJsonFile("Configuration/AmqpLoggingSettings.json")
.AddEnvironmentVariables();
this.Configuration = builder.Build();
17. Options model – bind to classes throught DI
public class AmqpLoggerOptions
{
public string ServerAddress { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string VirtualHost { get; set; }
public string ExchangeName { get; set; }
public string Facility { get; set; }
}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<AmqpLoggerOptions>(Configuration.GetSection("AmqpLoggerConfiguration"));
}
Startup.cs
18. public class AmqpLogger : ILogger
{
private readonly RabbitMqLogger logger;
private readonly AmqpLoggerOptions amqpOptions;
public AmqpLogger(IOptions<AmqpLoggerOptions> options)
{
amqpOptions = options.Value;
var rabbitOptions = Mapper.Map<RabbitMqLoggerOptions>(amqpOptions);
logger = new RabbitMqLogger(rabbitOptions);
}
public async Task<Guid> LogAsync(IActiveMashupsLogEntry logEntry)
{
var logMessage = CreateMessageWithDefaultFields(logEntry);
var loggingSucceed = await logger.LogMessage(logMessage);
if (!loggingSucceed)
{
throw new Exception("Failed to send logs to amqp");
}
return logMessage.Id;
}
Options model - usage
Build-in DI
20. Dependency Injection - Service Lifetimes
ASP.NET services can be configured with the following lifetimes:
■ Transient - Transient lifetime services are created each time they are requested. This
lifetime works best for lightweight, stateless services.
■ Scoped - Scoped lifetime services are created once per request.
■ Singleton - Singleton lifetime services are created the first time they are requested (or
when ConfigureServices is run if you specify an instance there) and then every subsequent
request will use the same instance. If your application requires singleton behavior, allowing
the services container to manage the service’s lifetime is recommended instead of
implementing the singleton design pattern and managing your object’s lifetime in the class
yourself.
21. Logging, middleware, routing
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMiddleware<LogBadResponsesAsWarningsMiddleware>();
app.UseMiddleware<ContentLengthResponseHeaderWriterMiddleware>();
app.UseStaticFiles();
app.UseMvc(routes =>
{
// add the new route here.
routes.MapRoute(name: "areaRoute",
template: "{area:exists}/{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
});
}
Startup.cs
22. Middleware (ex HTTP Module)
https://docs.asp.net/en/latest/fundamentals/middleware.html
23. Middleware example
public class ContentLengthResponseHeaderWriterMiddleware
{
private readonly RequestDelegate next;
public ContentLengthResponseHeaderWriter(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
using (var buffer = new MemoryStream())
{
var response = context.Response;
var bodyStream = response.Body;
response.Body = buffer;
await this.next(context);
var lenght = buffer.Length;
if (lenght > 0)
{
response.Headers.Add("Content-Length", new[] { lenght.ToString() });
}
buffer.Position = 0;
await buffer.CopyToAsync(bodyStream);
}
}
}
24. United controller
[Area("Portfolios")]
[Route("[controller]")]
public class PortfoliosController : Controller
{
public async Task<object> Get()
{
return await new GetPortfoliosWorkflow(this.HttpContext).ExecuteAsync(null);
}
[HttpGet("{portfolioId}")]
public async Task<object> Get(long portfolioId)
{
return await new GetSinglePortfolioWorkflow(this.HttpContext).ExecuteAsync(portfolioId);
}
[HttpPost]
public async Task<object> Post([FromBody]PortfolioViewModel portfolioViewModel)
{
var result = await new CreatePortfolioWorkflow(this.HttpContext).ExecuteAsync(portfolioViewModel);
var locationHeader = HttpContext.Request.GetDisplayUrl() + "/" + result.PortfolioId;
return Created(locationHeader, result);
}
[HttpPut("{portfolioId}")]
public async Task<object> Put(long portfolioId, [FromBody]PortfolioViewModel portfolioViewModel)
{
if (portfolioViewModel.PortfolioId != 0 && portfolioViewModel.PortfolioId != portfolioId)
{
return new BadRequestObjectResult("Portfolio id from url is not equal to portfolio id from request");
}
portfolioViewModel.PortfolioId = portfolioId;
return await new UpdatePortfolioWorkflow(this.HttpContext).ExecuteAsync(portfolioViewModel);
}
25. Kestrel
■ Kestrel is a cross-platform web server based on libuv, a cross-platform asynchronous I/O library.
■ You add support for Kestrel by including Microsoft.AspNet.Server.Kestrel in your project’s
dependencies listed in project.json.
■ https://github.com/aspnet/KestrelHttpServer
https://docs.asp.net/en/latest/fundamentals/servers.html
26. CLITools
■ The DNX Utility (DNU) tool is responsible for all operations involved with packages in
your application.
■ Dotnet version manager (DNVM) is responsible for downloading and installation
environment runtimes.
■ DNX is .NET Execution Environment that will execute your application.
27. Dotnet version manager (DNVM)
You can install any environment that is available on platform you are using.
Some useful cli commands:
■ dnvm list - will show you list of available installer runtimes, their aliases and current default runtime
(marked by *)
■ dnvm install - installs requested runtime (example - dnvm install latest -r coreclr -acrh x64)
■ dnvm use - selects specific runtime as default
(examples - dnvm use default; dnvm use 1.0.0-rc1-update1 -r coreclr -acrh x64)
28.
29. The DNX Utility (DNU)
■ DNU restore - restores nuget pakages
■ DNU publish - will package your application into a self-contained directory that can
be launched. It will create the following directory structure
output/
output/packages
output/appName
output/commandName.cmd
Note, that DNU can be unavailable if there is no runtime selected in DNVM (even if
runtimes are installed).
30. .NET Execution Environment (DNX)
In common case it's only used to run you app by execution from directory with
project.json file:
■ dnx web - for web app
■ dnx run - for console app
31. CLI tools from RC 1 to RC 2
DNVM, DNU, DNX = > Dotnet
DNX command CLI command Description
dnx run dotnet run Run code from source.
dnu build dotnet build Build an IL binary of your code.
dnu pack dotnet pack Package up a NuGet package of your code.
dnx [command] (for example, "dnx web") N/A* In DNX world, run a command as defined in the project.json.
dnu install N/A* In the DNX world, install a package as a dependency.
dnu restore dotnet restore Restore dependencies specified in your project.json.
dnu publish dotnet publish
Publish your application for deployment in one of the three forms (portable,
portable with native and standalone).
dnu wrap N/A* In DNX world, wrap a project.json in csproj.
dnu commands N/A* In DNX world, manage the globally installed commands.
(*) - these features are not supported in the CLI by design.
32. Known issues
■ Kestrel do not set content-length header in response.
If your component needs this header (for example, java-based vert.x uses content-length
to read message body), add middleware as workaround.
■ While working with 3rd party datasources, especially withWCF SOAP (IIS) services,
server can send response with GZipped content + content-length (header) of GZipped
body.
System libs fails to deserialize response body, they UZipping body, but reads it using
content-length header of GZipped body.
Thus, body can be read only by half of its contents.