 So our next speaker is is Juergen. He's gonna be talking to us about ASP net core customization customization Let's get him brought in here. There we go fly from London. Get ready. Get your wings up. Get your wings out Here we go Well, it's not going as far. It's taking about the same amount of time And there we go, we're going into Germany and Where'd it go? There's Juergen We've got your screen Here you there. Go ahead, Juergen. Go ahead. You there Juergen? Hello The whole stack from the top from HTML, CSS, JavaScript to C-Shark. I'm a Microsoft TVB for developer technologies as you call it now. I'm blogging on ASP.net at shaker.rux. I also write articles in the German dev magazines leading a user group in Basel and maybe the last in-ear organization worldwide, I'm sure. I'm working in Zipfler So, I live in South Germany. We're in Switzerland in Basel at the UPSM Company. You know, you have a lot of projects from me on GitHub. Also, the searches of the demos that I do are on GitHub. The link is in the center slide. Yeah, that's the agenda for today. We have about 10 different topics and because of which of the topics during the demos, it's okay to ask questions after the demo. It's also fine for me. The first topic is about logging, how you customize your logging or add a custom logger or whatever you want to do. We go through configuration, dependency, section, HTTPS, and hosted services. We really like the hosted services to do something in the background. We go through middleware, start with formatus, model blind section filters can help us. As you can see, we're going from the C sharp back end up to the view. Let's start with our switch of PowerPoint here because we don't need it anymore and go to the console. The first thing I will do is go to a different solution for this. The first one is to go to the first one about logging and create a new MVC application. I'm really a fan of the console and there's a lot of stuff in the console. Same as creating new ASP.NET code projects, in that case, create a MVC project. I'll name it LoggingSample and put it into an Output Directory called LoggingSample. So create that and that's all the Nougat Packs needs after that HTTPS to that Voter. So we use this suit console here to see more of the output. What later do we have to do is we need to look to the output in a small detail here in the bigger console than in the terminal and it's a code. SoundProjects open and also live code because it starts really fast. Let's have a look into the logging in previous versions. We had some logging configuration in the startup. That's not there anymore, I think. It's now encapsulated and held in this in the default configuration here. We create the well-posed, we create it with a default bidder to configure the logging now. So I'm able to overwrite the logging configuration using an extension method to configure logging. What you see here is exactly what is hidden inside. There's a logging configuration that's loaded from the app settings JSON. And then a console logger or debug and a debug logger is added to the logging here. So that's pretty much it. We don't have any logging into a file or logging into a database or whatever. So what I want to do now here is to create a custom logger and put it into this configuration. What I need to have first is something like a logging configuration. That's needed in my case. I will configure the logger to handle specific log levels. In that case it's a warning level. I have an event ID which I want to handle and a color. This is a simple color console logger. In that case it's nothing sensible but it describes how we can create a custom logger here. So after that we need a logger provider. This is the thing that gets put it into the logging configuration above. We'll see it later on. We need to add some dependencies here. And last but not least we need to add the actual logger. So I copy paste code snippets from the other window because I'm pretty sure you don't want to see me typing code here. It's too much. And that's the actual logger. It arrives from iLogger. Here we get the configuration in here. We can set an iLogger name and so on. We can create a scope if needed. We can figure out whether it's enabled or not. And that's the actual log function here. And what this logger does is it creates a colored output of a specific log levels. So nothing special here. So now we need to add it to the configuration. So first thing we do is we clear the providers. And we add a new configuration here. And then we add the new logger provider. That's our colored console logger provider. And we pass in the configuration. So all information log-info's should be colored in red. So let's try it out. I go back to the console and write .NET RUN. And we already should see some red log entries here. So we still use the console logger here and the debug logger. So this is the information log-info. And let's get colored in red. Doesn't make sense actually. But it's nice to see how the logger and logger provider works. And all the other informations are also colored in red. So a more real world scenario is to add a real logging engine. So for example, unlock. So to add unlock, we need to add a package to a project. So we shut that down. We shut that down. Click on the screen. Answer.NET at package unlockweb.asp.NET core from Nougat. A little bit. So it's in. Also now I need to add some usings. Unlock extensions, logging. Unlock web. And I need to add unlock config. Unlock config. Usually unlock is configured using XML config file. So let's get loaded here. And I add the actual unlock logging provider. Command that out. So the next thing is we need to add the unlock config to a project. And I'll paste some xmux in. So what this configuration does is to define two different logging things. One is to lock all stuff. And the other locks only custom log entries. So this is defined here. This one adds all and this one only adds microsoft.something. So let's run it again. This is our right path. Yeah, it seems so. So we should get one configuration file, one logging file here. And our folder. So let's start it again. Let's have a look into our working folder one second. Here's our unlock logging file. Let's do something on the web. Just taking around. It does something. Now let's have a look into that file. Oh, it opens another wrong window. I have three monitors here. So that's the lock file. So on this way you're able to create your own custom logging providers. Or add some other lockers like lock for net or whatever you want to add. Unlock is nice because it already has unlock logger provider implemented. And you can simply plug that in. So yeah, any questions? If no, we'll jump to the next topic. Okay, I hear. So let's jump to the next one. So I'll go to the configuration part. Also this can be customized. Also here I create a new MVC project. The same way, different names, different output folder. Can close this editor path and into CD to the configure sample. So like this, like the logging part. There's also no configuration configure thing here in the startup as in previous versions. So we only have this configuration. This is already configured. That passed in into the startup and can use it. The actual configuration is also hidden inside the default builder. So here's where we can override all these configurations here. And this also exactly what is configured inside the default builder. So we have this environment here which gets passed in with this builder context. This environments tells us whether we are in dev or environment, in development mode or production or staging mode. We also set the base path. That's the content root path. This should be the adoptive root folder here. And we add some JSON files. We have the app settings JSON and we have the app settings something JSON. Something is the environment name here and we see that here. We have the app settings.json and the app settings.development.json. So the second one is optional. The first one is not optional. So the second one is able to override the settings from the first one. So that's pretty clear, that's standard. Also load the environment variables usually as the last instance. We'll customize some things here and the environment variables configurations should be the last one just to override all the previously defined settings. So let's have a look here. That's the standard app settings JSON. Simply put another node here and call it app settings. We have a setting called foo, another setting called bar. And to load that app settings in is pretty easy and straightforward. So that's simply done by creating app settings class. I do it here in the startup. Usually you should do it in a separate file. That's my app settings class. And I'm able to load that in the service configuration. Now we configure our app settings class with this configuration section called app setting. So then we can use the app settings in our home controller. It's also pretty clear. So just do it now. That's our app setting. We pass it in with an iOptions object. We access our app settings via the value object of this iOptions object. And then we use that. This time I implement all this stuff here because we need to test some more configurations later on. So I go to the index. This is HTML and pass in some more simpler code than that. So I'll delete that. And just show the title and the message. So let's do that. Just to see that our app settings class is working. So it's building. Let's call the home page. Yeah, we get that bar from our configuration. It's that thing here. So what we also can do, we can load settings from different other files. So let's go back to the programs here. Let's see what else we have in the config object here. So we have the add command line. So we can use our command line options to configure applications. We can create an in-memory collection, which is just a key value collection. We can load key per file. So each file name is there's a configuration key and the content of the file is the content of the configuration value. Or user secrets, which is built in, I think. We can load configurations from XML files and as well from any files here. Let's try this. So I'll call that app settings any. Also use these other options here. So these methods look pretty cool. This should also be any file. And then we are able to create the app settings any. App settings.any. Okay, let's add some values. The bar value here should work. Now we should get the value of foobar presented on the index page. So let's rerun that. Refresh the page. Now it's foobar. That's the value from the any file. So from the community there's a lot more configuration providers available for YAML, for example, or maybe to load configuration from a database or whatever. And you're also able to create your own configuration providers. Are there any questions about this topic? Let's stop that. Jump to the next one. We actually do have a few questions, so if you want to take some now. Yeah, sure. So we had some questions here. Yeah, free for you to ask. Oh no, no, there was a question about console log. Yeah, so Jurgen, there was a question about console log. I'm just asking if we want to ask some questions from the audience. I'm free for you to do it. We have one coming right now. So there was a question about console log. And when you were using console log, you wrapped it with a lock when you wrote your console logger. Was that because it's not thread safe? I can't hear anymore, sorry, the audio stopped. You can't hear us. Sorry, we had a question about console log. You wrapped it in a lock statement. Is that because it's not thread safe? You're talking about the custom logger, right? Right. That's why you wrapped it. I've wrapped it because I want to log in in the right order. I want to confuse with the order. Maybe we don't need this. I had some issues with the coloring that there was a race condition between the different log entries then. So the wrong log entries get colored in the wrong color. Oh, that makes sense. Thank you. Okay, good. Let's continue with that. Next topic is dependence injection. That's one of my favorite topics because I maintain the Litecore project. It's a pretty fast dependence injection container. I also tried it to get it running on ISP.NET Core. And you're really able to replace the existing dependence injection container with a custom one. And in this demo, I tried to do that with the myth, what's its name? Autofac, yeah. I did it with Autofac. So the project is done. CD2DI sample. Also open that in a new code window. Close that. Oops. Close that code dot to open the new project. And the first thing I'll do in the startup, I create a small service class under DTO. Just to demo the dependence injection. Put it here. Just to keep it simple. So this is sometimes the code formatting shortcut doesn't work. This is a small service which creates a list of 25 persons. Yeah, we need that. We also need a dependency here. Another Nougat package, which I really like. It's genfoo.net add package genfoo. And this is a really small use for library to create test data. And now it's in. Change back to code. We need to restore it here. The small pop-ups also shows up if I do a restore in the console. I don't know why. So I use genfoo here. So I'm going to create a list of persons of 25 persons in that case. So let's go back to the startup. So the configuration of the DI container is done in the configured service. So we get a service collection here. We can add a lot more services. We get some services here. Some options. And we get a bunch of services inside this at MVC. So I recently counted all the services registered. And it has done that asp.net core application. Including, I think, security identity stuff and so on. And we have 140 services registered without the custom ones. Yep. To add an own dependency injection container, we need to change this method to configure services a little bit. So it's absolutely legal to change the signature. Oops. So I can return an iService provider. And I'm able to create a service provider out of the service collection. Services build service provider. That's it. So this still works. This is absolutely okay to change the method like this. So what I wanted first to demonstrate dependency injection is to change the home controller a little bit. Sorry, because it jumped a little bit around here. So I request the iService inside the home controller and I changed the razor view of, let's use the about view a little bit. So that's the smallest one. Well, let's use contact. Makes more sense. So I add a for each loop here. And the rest is done later. Right. I'll go back to the controller. And change this part. So I use the iService request or persons and return the persons back to the view. So we have a list of persons in the view. We need to change the model a little bit. Model and enumerable of person. I think it's the iSamplePerson.Person. That should work. Okay. And then back to startup. Let's try whether this is working or not. So I registered the service here. So currently it's still the, that's a little bit wrong service add. Transient a little bit too fast here. Sorry about that. So we have the aService and myService and then So that should be the default registration way. So that's surely need to have a look whether this is working or not. Do not run. So I want to ensure that all the service collection configuration is working before replace the DI container with the autofuck. So that looks good. Let's go to the contact page. And this is working too. So here we have the list of persons generated by GenFu. So until now this is the default dependence injection. We should use in ASP.core. So now let's replace this with autofuck. To do this we need autofuck extension. This is a nugget package. We call .NET add package again. This autofack.extensions.dependency injection. Let's load that. We need to restore it at the autofack configuration. So these are some lines of code. This could be wrapped in a different method. I'm going to put it in here. So we don't return the standard service provider. We use the service provider from autofuck in that case. So autofuck works the same way as Lightcore. So we need to create a container builder first to create the DI container. And the container builder then builds the actual container. So this is a property we need to add here. So we store it in the startup to reuse it. And then the application container. The container gets passed into the autofack service provider. You can also create your own service provider if you want to maybe support some other dependence injection. I'm not sure if NINJECT currently brings its own service provider. But when I last tried it, I needed to create the service container by myself. So this is special here because we need to register all the already registered services inside the autofack container. So that's what this method does. So it collects all the services from the service collection and puts the services inside the container builder. This should work. And we can remove this registration and activate that one. So this is the autofuck way to register services. So we should register type as on contract. Okay. This should work too. Let's rerun it. So when should you replace the default dependence injection container? Usually it doesn't make sense because the current one works pretty well. But there are some other dependence injection containers with nice features. For example NINJECT can have a look into a folder and search for assemblies with the right services inside. And so on. So there's an auto registration in NINJECT for example. And maybe you like these features and want to use it in ASP.NET Core 2. Okay. It's working. On every refresh we get a new list. It's implemented like this but you see it's working. We get this list of persons here. Good. Do we have questions about this topic? I think I need to get a little bit faster through the topics here. Okay. Let's go back. Next one is HTTPS. That's a small one. Let's create the project and open that. HTTPS is enabled by default since 2.1 I think. But currently it's working using the Windows certificate store on Windows. On Linux and Mac you can pass in your own certificate file. Sometimes I really like the idea to use a specific certificate file instead of using the certificate store on Windows. And you can use this in ASP.NET Core and Windows too. So let's open that. Well, as you can see in this startup we already have some configurations about HTTPS. So we have an HTTPS redirection here so that redirects the HTTP request to HTTPS. I also have this HSTS middleware here to enforce a certificate validation. And also hidden in the program CS we have the configuration of HTTPS. So we can start already listening on the HTTPS port. So this is configured in the program also hidden in that method. We can also override this. And to use our own certificate file we can add a port here which should be listened on. We register the address of the port and some listen options. This options enables HTTPS on that port and we can add a certificate file here. So this is a certificate pfx and a top secret password. And also this should work if I drag and drop the certificate in here. That doesn't work here. I'll drop that in. That's weird, I don't see that. It was a Dropbox error. So the certificate is here now. Here it is. We can start it up. This won't work because of the wrong host name. Currently the certificate is created for local host and not for this IP address. I'll try to read that. It will work. So it's a secure connection with custom certificate file. So usually on Windows you should use the certificate store. But sometimes it's easier maybe to change to a specific file. In a special case when you want to run the applications on Mac, Linux and Windows without different configurations. That's about HTTPS. The next topic is about the hosted services. So I really like hosted services. It's a feature to run a task in the background of an application. So this is also a quick demo. Let's create a new MVC application. Let's see the host and services. Open that in code. Also to give it a simple, I put the hosted service class in the startup. What's that? No document form out of a C sharp file. It worked previously. Let's do it like this. So the hosted service is derived from hosted service. It's a simple class, nothing special here. We pass in a logger here because I want to show the background task via the console logging. And we have a start async method and a stop async method. And usually we start doing the task in the start async class and clean up some things in the stop async method, sorry. And then we create a new task factory and do some stuff in a while here. So it's only about logging. It waits for two seconds and continues logging. Pretty simple. So we need to add these usings here. We need this. All green now. And all we need to do to get the hosted service running is to register it in the DI container. So we add it as a singleton. Add a high hosted service and the actual class. Now it should work. That's right. It's launching. It's up and running. So all two seconds logs an entry out. Now it does some more and it still logs. So it works in the background. You can use these to do some background tasks, fetching some data from somewhere or whatever you want to do in the background. So we like this feature. So let's stop it and unstop. We have this log output here, hosted services stopping. Any questions about that? The next topic. So the next one is middlewares. So also create a new project and that's in this case an empty web project. It's not MVC here. It's web which is an empty one. Open that in code. That's the wrong folder. And if you open the startup we already see two middlewares. I think one or two. Yeah, we see two different middlewares here. You have this middleware which renders out a string which is only hello world and then text format. And we have this developer exception page which is also a middleware that checks for errors in the pipeline here. So we can put some things into the pipeline, some more middlewares to show how middlewares are working. So the ordering matters here. That's important to know. So the first middleware gets executed as the first one and the second one is the second place and that's the last one. So we have two different kind of middlewares. We have the abuse middlewares. Which are calling a next middleware. The next one is this one. And also this is calling the next middleware which is that middleware here. And this middleware doesn't continue to another middleware. So it stops here, the pipeline stops. And the execution gets back up to all the middlewares. So we see that in a second. So let's run that. That's running. So that's the first string, the second string. That's the string of the first middleware from the second middleware. That's the last one and it goes back. We can create a lot more middlewares. For example a real-world scenario is stopwatch. You can add a stopwatch here. This is the same thing as the other one. But it actually does something maybe useful. So it measures the execution time here. And writes out the time needed. Let's rerun that. It says we need 10 seconds. Now it's cached, almost cached. It's working. We can do some more with middlewares. We can add routing, something like routing. It's custom routing. We can define a middleware which is mapped on that route here. So we can continue the pipeline inside this map. And the same with a different map. No one wants to use these kind of middlewares. I think the most common way to create middlewares is to create a middleware class. I'll do the same method here. Same class, sorry. This is stopwatch middleware class. That's a normal stupid class here. And usually we should write a nice extension method to use this middleware. So we can write app.use stopwatch. So this should work as well. So I don't demo that because we are running out of time. I think one more interesting thing are the next topic. I think the output form it is. Let's go to that one. Create any msd page, msd project, and cd to that. So Jurgen, while you're setting up this demo and we get into the last few minutes here. Some folks were asking, why would you set up a certificate in ASPNet Core instead of using IIS or Nginx as a proxy? Maybe I self-host this application or it's just hosted in Kestrel running somewhere. I'm talking about running the web without an IIS or Nginx or something like this. Sure, it's nice when you're in a container and you don't really need all that front-end ceremony with Nginx or IIS. Exactly. Then when you showed us a little bit about using autofac, that isn't really needed, right? That's nice to have if you really need some of those extended features of autofac for dependency injection. What kinds of things do you see using autofac in that model for? What are the real things that make you say, oh my gosh, yes, this is why I need to use autofac? I use autofac because it's an easy demo because they already implemented service provider. But I really like the features of NINJECT, for example, to auto-register classes and services from different assembly. I can tell NINJECT, please look in this directory and load me all the needed services. That's a nice feature of NINJECT. You can use any other DI container which, for example, has this feature inside. Autofac is also pretty simple, unlike the ASP.NET core dependency injection container. Very cool. We're just about out of time. We've got about five more minutes. I'll let you wrap up your demo there and take it away. Okay, thanks. I created the Output Format Assemble project. I open that in code and create a simple API controller. Let's do it here in the NINJECT file. I call it PersonsController. PersonsController.cs Paste in another class. I also create a Person class. I put it into the same file here. Keep it simple. I add an action to that controller. Formatting won't work here. Now it does. We also need GenFu.NET Add package GenFu. It's passed in. Until then, I add some dependencies using this. That should be in now. Code needs some time. Using GenFu. We have PersonsController here. The goal is to register Output Format Assemble to not only output the Persons in an adjacent format. But maybe in CSV or in a vCard output as well. What I need to do is to register some Output Format As. This is done in startup. Yes, it's done in startup in the registration of MVC. I add some MVC options. I need that. This doesn't work currently. I need to add the Output Formata classes. The first one is the vCard Formata. Paste that in here. The second one is a CSV Output Format. For the CSV part, I need another dependency, which is CSV Helper. While this gets in, I can start to the Usings. This is Microsoft.NET Encoding a system text. The person is on the controller side. Here we need the logger and the CSV writer. The code needs some more time to think about the CSV Helper here. This is needed, SystemIO. Now it should work. There are just the two different Output Format. The one is vCard and the other one is CSV Output Formata. Here we have from registration. Let's see how it works. That was pretty fast. Sometimes namespaces get confused in the startup. The web is still running, hopefully. I already prepared the request in Postman. Postman is a nice tool to do web API requests. Here we have a request to the person's controller. I try to do the application JSON. That's the default behavior here. I send the GET request to the person's controller and get a nice JSON result. If I change that to text. Come on. Text CSV. Then I get a CSV result. We accept different formats here. When you say accept CSV, we get CSV. If you say we want to have text vCard, we get the vCard result. Now we have real vCards. We can import that in Outlook and Sun. This is a nice way to change to various outputs. Like Excel, Word. I also did a Word Output Formata. That is awesome stuff, Jürgen. It's great to see that the Output Format is in ASP.NET Core. Web API are still there and there are still great things that we can use. So that Web API can learn from what type it is that you're requesting and just respond and reformat stuff without you as an API author having to go and write all of that translation stuff. Like I might do if I was writing it with a razor page, right? Yeah, exactly. Awesome. Do you have a list of resources for us here as we wrap up the session? Yeah, I have all the stuff in GitHub. So let's have a look. So it's all here. There it is. We create a repository with all the stuff and all the demos. So that way. So very cool stuff. Thank you so much, Jürgen, for joining us here at .NET Conf. We really appreciate you taking time presenting, walking us through all this stuff. For everybody in the chat room, if you like what you saw, this will be archived and it'll be over on YouTube a little bit later and we're going to be rerunning all of .NET Conf all weekend long. You're going to be able to watch anything that you may have missed or if it was airing during a time zone that wasn't during a time that wasn't good for your time zone, you'll be able to check it out. So thanks so much, Jürgen. We really appreciate it and we'll catch you later, buddy. Thank you. Thank you. All righty. And we're going to disconnect. Fantastic. There we go. So Brady and I are here. He's sliding right in. Brady Gaster, hello, hello. How's it going, everybody? Good morning. We're closing in on 6 a.m. Pacific time. We're into hour 13 of the 24 hours of .NET Conf. Good morning, Thinkbot Labs. Great to see you. We've got some more great content coming up. We're going to be bringing in Edward Thompson in just a few minutes. He's out in London, right? Cambridge. So you've got him all set to go over there. We're going to go to a quick break while we get Edward dialed in. Hope you stick around with us for the next hour. Sliding right in, a strange name. Yes, there he is, Brady Gaster. And there he goes. So stay tuned. We're going to get Edward all set up here and we'll see you in just a minute.