c#on linux
TRANSCRIPT
![Page 1: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/1.jpg)
C# ON LINUXOur experience
![Page 2: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/2.jpg)
Different naming
■ ASP.NET 5■ ASP.NET MVC 6■ ASP.NET vNext■ ASP.NET Core 1
![Page 3: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/3.jpg)
Visual studio changesThe Node Package Manager is fully integrated with Visual Studio to provide a more natural user workflow.
![Page 4: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/4.jpg)
GRUNT / GULP / BOWER Integration
![Page 5: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/5.jpg)
Task Runner Explorer
![Page 6: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/6.jpg)
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/
![Page 7: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/7.jpg)
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.
![Page 8: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/8.jpg)
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
![Page 9: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/9.jpg)
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 }}
![Page 10: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/10.jpg)
Many platforms in-time development
![Page 11: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/11.jpg)
![Page 12: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/12.jpg)
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
![Page 13: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/13.jpg)
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
![Page 14: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/14.jpg)
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); }
![Page 15: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/15.jpg)
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;
}}
![Page 16: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/16.jpg)
Options model – load configurationhttps://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();
![Page 17: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/17.jpg)
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
![Page 18: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/18.jpg)
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
![Page 19: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/19.jpg)
Build-in Dependency Injectionhttps://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
![Page 20: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/20.jpg)
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.
![Page 21: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/21.jpg)
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
![Page 22: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/22.jpg)
Middleware (ex HTTP Module)https://docs.asp.net/en/latest/fundamentals/middleware.html
![Page 23: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/23.jpg)
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); } } }
![Page 24: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/24.jpg)
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); }}
![Page 25: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/25.jpg)
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
![Page 26: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/26.jpg)
CLI Tools
■ 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.
![Page 27: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/27.jpg)
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)
![Page 28: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/28.jpg)
![Page 29: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/29.jpg)
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 structureoutput/output/packagesoutput/appNameoutput/commandName.cmd
Note, that DNU can be unavailable if there is no runtime selected in DNVM (even if runtimes are installed).
![Page 30: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/30.jpg)
.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
![Page 31: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/31.jpg)
CLI tools from RC 1 to RC 2DNVM, DNU, DNX = > Dotnet
DNX command CLI command Descriptiondnx 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.
![Page 32: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/32.jpg)
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 with WCF 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.
![Page 33: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/33.jpg)
RC2, RTM and future
![Page 34: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/34.jpg)
QUESTIONS?
![Page 35: C#on linux](https://reader036.vdocuments.us/reader036/viewer/2022062903/58ed11c11a28ab7d328b47db/html5/thumbnails/35.jpg)
Thanks!
MAKSIM VOLK Software Engineer
Office: +375 17 389 0100 x 40673 Cell: +375 29 365 6597 Email: [email protected] Minsk, Belarus (GMT+3) epam.com