SlideShare a Scribd company logo
C# ON LINUX
Our experience
Different naming
■ ASP.NET 5
■ ASP.NET MVC 6
■ ASP.NET vNext
■ ASP.NETCore 1
Visual studio changes
The Node Package Manager is fully integrated with Visual Studio to provide a more natural user workflow.
GRUNT / GULP / BOWER Integration
Task Runner
Explorer
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/
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.
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
Project.json
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-rc1-final",
"Microsoft.Extensions.Logging": "1.0.0-rc1-final",
"Microsoft.Extensions.Caching.Abstractions": "1.0.0-rc1-final",
"Microsoft.Extensions.Caching.Memory": "1.0.0-rc1-final",
"System.Console": "4.0.0-beta-23516",
"System.Linq": "4.0.1-beta-23516",
"Trkd.Dnx.Proxy": "1.0.0-*",
"ActiveMashups.Core": "1.0.0-*",
"System.Runtime": "4.0.21-beta-23516",
"System.Collections": "4.0.11-beta-23516",
"System.Linq.Queryable": "4.0.1-beta-23516",
"System.Linq.Parallel": "4.0.1-beta-23516",
"System.Threading.Tasks": "4.0.11-beta-23516",
"System.Runtime.Serialization.Primitives": "4.1.0-beta-23516“
},
"commands": {
"web": "Microsoft.AspNet.Server.Kestrel"
},
"frameworks": {
"dnxcore50": {
}
},
"exclude": [
"wwwroot",
"node_modules"
],
"publishExclude": [
"**.user",
"**.vspscc"
],
"scripts": {
"postpublish": "%project:Directory%/postpublish/postpublish.bat"
}
}
"frameworks": {
"dnxcore50": { // .Net Core
},
"dnx461" :{ // mono
},
"net461" :{ // .Net Framework
}
}
Many platforms in-time development
C#on linux
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
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
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);
}
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;
}
}
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();
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
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
Build-in Dependency Injection
https://docs.asp.net/en/latest/fundamentals/dependency-injection.html
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(
mvcOptions =>
{
mvcOptions.Filters.Add(typeof(GlobalExceptionInterseptor));
mvcOptions.Filters.Add(typeof(JsonWebTokenAuthentification));
});
ConfigureOptions(services);
services.AddSingleton<AmqpLogger>();
services.AddSingleton<FileLogger>();
services.AddTransient<ILogger, AmqpAndFileLogger>();
services.AddSingleton<ITokensManager, TrkdTokensManager>();
}
Startup.cs
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.
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
Middleware (ex HTTP Module)
https://docs.asp.net/en/latest/fundamentals/middleware.html
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);
}
}
}
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);
}
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
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.
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)
C#on linux
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).
.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
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.
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.
RC2, RTM and future
QUESTIONS?
Thanks!
MAKSIM VOLK
Software Engineer
Office: +375 17 389 0100 x 40673 Cell: +375 29 365 6597 Email: maksim_volk@epam.com
Minsk, Belarus (GMT+3) epam.com

More Related Content

C#on linux

  • 1. C# ON LINUX Our experience
  • 2. Different naming ■ ASP.NET 5 ■ ASP.NET MVC 6 ■ ASP.NET vNext ■ ASP.NETCore 1
  • 3. Visual studio changes The Node Package Manager is fully integrated with Visual Studio to provide a more natural user workflow.
  • 4. GRUNT / GULP / BOWER Integration
  • 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
  • 9. Project.json { "version": "1.0.0-*", "compilationOptions": { "emitEntryPoint": true }, "dependencies": { "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final", "Microsoft.AspNet.Mvc": "6.0.0-rc1-final", "Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-rc1-final", "Microsoft.Extensions.Logging": "1.0.0-rc1-final", "Microsoft.Extensions.Caching.Abstractions": "1.0.0-rc1-final", "Microsoft.Extensions.Caching.Memory": "1.0.0-rc1-final", "System.Console": "4.0.0-beta-23516", "System.Linq": "4.0.1-beta-23516", "Trkd.Dnx.Proxy": "1.0.0-*", "ActiveMashups.Core": "1.0.0-*", "System.Runtime": "4.0.21-beta-23516", "System.Collections": "4.0.11-beta-23516", "System.Linq.Queryable": "4.0.1-beta-23516", "System.Linq.Parallel": "4.0.1-beta-23516", "System.Threading.Tasks": "4.0.11-beta-23516", "System.Runtime.Serialization.Primitives": "4.1.0-beta-23516“ }, "commands": { "web": "Microsoft.AspNet.Server.Kestrel" }, "frameworks": { "dnxcore50": { } }, "exclude": [ "wwwroot", "node_modules" ], "publishExclude": [ "**.user", "**.vspscc" ], "scripts": { "postpublish": "%project:Directory%/postpublish/postpublish.bat" } } "frameworks": { "dnxcore50": { // .Net Core }, "dnx461" :{ // mono }, "net461" :{ // .Net Framework } }
  • 10. Many platforms in-time development
  • 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
  • 19. Build-in Dependency Injection https://docs.asp.net/en/latest/fundamentals/dependency-injection.html public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc( mvcOptions => { mvcOptions.Filters.Add(typeof(GlobalExceptionInterseptor)); mvcOptions.Filters.Add(typeof(JsonWebTokenAuthentification)); }); ConfigureOptions(services); services.AddSingleton<AmqpLogger>(); services.AddSingleton<FileLogger>(); services.AddTransient<ILogger, AmqpAndFileLogger>(); services.AddSingleton<ITokensManager, TrkdTokensManager>(); } Startup.cs
  • 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)
  • 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.
  • 33. RC2, RTM and future
  • 35. Thanks! MAKSIM VOLK Software Engineer Office: +375 17 389 0100 x 40673 Cell: +375 29 365 6597 Email: maksim_volk@epam.com Minsk, Belarus (GMT+3) epam.com