 We're live okay. Thank you so much for bearing with us. I think there was well sets push that one red button and obviously That's what happened. Okay. I'm Kendra Havens. I'm here with Sebastian Ross Okay, and we're here to talk about building modular multi-tenant ASP.net core apps with the orchard core framework But it's actually gonna be super understandable I hope so. For me it is. Yeah. The goal is to make it understandable. Yeah, okay I'll ask questions and we'll we'll see how we do. So I think you have some slides Do we want to jump in already? Switch are the best slides. Actually, why don't you introduce yourself first? What do you work on? So I work on Microsoft and the ASP.net team and mostly on performance and orchard core, but just a little Just a little from some benchmarking and just a little bit of orchard core. So I know what I will be talking about Yeah, that's just an expert. Oh, no trickle. That's it. Yeah, and the throughput also RPS. I know RPS. All right My slides Well, wait, wait, maybe I need to read to reconnect my Yeah happens So here's the weird thing Okay, no slides. It's just talking But if I if I turn my screen and we Happens any idea master for it every problem as a solution Oh, it works Okay, so try to switch back Just for testing me. Okay. So let's start then Yeah So the title is building modular multi-tenant ASP.net core applications with orchard core but the first question is about modular applications and Why you would build modular applications? so most of the time Modular applications is to work in isolation like each project project is isolated from Every everything else and you might do that because You work with multiple teams and each team wants to own a different section of the application So we'll have to split the work and each project with each team in your environment Or it might be because you want to reuse some of the parts of your application these modules For instance, let's say they these parts these modules contain static assets like scripts images or middleware like authentication and You I like user management or dashboard Why and these pieces of your application you want to reuse them across applications? you will want modules and Last thing Imagine that these modules these parts of your application you want actually to develop them as a community and Publish your components on a public feed like you get you get gallery or any other gallery and With modules you can do that and create Reusable parts public parts that will help you make some more global ecosystems of application components Let's say like a CMS or an e-commerce that anyone could publish modules for that That's the goal of making modular Now, how do you do that in a spinet core? Auto core framework is a solution But let's see how it works Concretely if you want to use auto core framework to build more your applications so I will switch to a visual studio and I have a solution ready with A web application that is based on the empty Template in visual studio when you create a new web application This empty template has a start-up Class that has a configure method that will just return hello world from the home end point In a middleware. Okay. So if I run this app Very simple It will just output hello world like this now I Want to extend this application with a separate module. So here I have a class library that I called e-commerce This is a simple SDK web class library that I Make as a library you're targeting the netcorp 3-0 target and it has a start-up like This empty app thought up So a start-up class like any spinet core app with a configure method that will map a specific endpoint to responding e-commerce The same way. So I want to be able to make that part of my application So when using ultra core framework to do that, we will need to convert this app into a Modular app host and this class library to a module to do that we will use new get packages which are new get all and Are made for a spinet core 3-0 so here I will go manage my new get packages and browse For new get all packages and because this is the host application. I will import the Ultra core application targets Package which will convert my application to a modular host application So this is done and this application this class library. Sorry, I will do the same thing Managing get packages But this time instead of the application target, I will use ultra core dot module So adding a new get package. Sorry not this tab but The browse tab This is the package I want and I will install this package So now each of the components are ready, but in my startup I will need to use the services provided by ultra core. So I will do services that Add ultra core Oops, why did I break it? because I wrote that add ultra core and In the middle where I will use the Ultra core middleware so My application is ready to host modules This class library is a module and my services are configured to accept modules if I run this app again You will see that it should not work so if I try to access the e-commerce and Point it doesn't work because I need to tell my application to use this module and to do that We just add a reference to this project and with that the services will find this package as a module and Plug all the startup from these modules into my host application And so by doing e-commerce. I have my end point working in my host application So now you see how we can create a modular host application and a module now the goal of modules is to be reusable It's one of the goals. So let's see if I can create another app and reuse this module. So to do that I will create a new project That will be a core web application and I will base it this time With a more complex example on a web application. So a web application in espionette. We will configure razor pages from the espionette MVC framework So I will say create and I have this web application that will make the main application Just run it to see that it works correctly and I have a more complex app than my empty app Which contains a razor page, which is defined as a home page So let's add this module to this app and the same way we did earlier. I will add Then you get package to the new application But this one will be an MVC one because it will understand all the MVC concepts to make it modular and then with that I can do the same thing as the other app to remove ad razor pages But with a twist by saying add MVC To support the services for MVC which will replace the ad razor pages. It's included there and also here I don't need authorization. I don't need this call. I will do that by just calling use Orchal core the same way. So same thing with two lines of code and one package. I made this app modular host application and I will reference The module e-commerce that we created earlier and was working in a standard web app Run the application still working but now I Can access the endpoints defined in my module So the nice thing here is that same module is used from an empty app that doesn't know about an MVC or this app that knows about MVC and This is a simple module, but what if I want to create a module that has more Things to provide in this case because I'm working with MVC We want to create a module that will contain some MVC concepts. So let's Try to do that. I will add An existing project that I have pre-created before Which is called web API because it contains some web API. So this is Web project that is a library and that references the module targets. So it's a module but Like The e-commerce module it has a startup which is empty. That's nothing though. It provides a controller This is the weather forecast controller from the the default template for I think the API project template and this one is a standard MVC controller that is Routed to the control name. So this should be weather forecast and that will return on any get a list of forecast As a get all into JSON results. Okay, so this is a module. So I just need To reference it from my host application, which is a MVC host With web API and now this app Is made of its own startup and Two different other modules the e-commerce modules and the web API module and this one provides a weather forecast API. So if I run my app It's still working and I go to weather forecast I See that it returns the JSON and the result is coming from my external So that's the first step. We can have web APIs Using the routing system and point routing system from espic or MVC From external modules and you can see that you can extend your applications just by referencing an existing module So let's go a step further and add more Components to this module. So here. We just have a web API controller, but what if I want view controller Or a controller that will return a view. So I will add a new class Wait, I will copy paste this class and I will call it Home controller and remove all the things here Generate from controller Call it home controller and Simply have an index method that will return a view and This view that I will create in the home folder to match the controller New item I want to resolve you add and Here I will just say Hello from home Okay, so I have a home controller and the default route for a controller will be the name of the controller and the action and I won't change the route for now just to show you how it works And I will be there will be two steps to make it work correctly. I run the app. I Don't change anything. I just change my module, but I don't change the app and here to access this controller I will do web API slash home slash index And you see here. Hello from home So the first thing you notice is that it's not home slash index like on a standard app It's web API slash home slash index because a default convention for modules Controllers and routes is to prefix them with the module name Just to prevent collisions from modules, but I could very easily add a custom route like My home or even a convention one, but okay Let's try with my home and read it again and access the same thing So you see here you can also redefine from a module how you want to expose it and I could also have done it from the host app to Customize each modules route for the specific application Now the next thing you will notice is that this view doesn't use the layout of the host application This is just because we need to say it in every view So in the host application the views which are razor pages here Are using a view start that will set the layout to the shared layout in this host application if I take this code and put it in my view or in a view start under the views folder of the module I Will get the same result so by doing that and running the application. I get the same Layout as the host application, but from a view which is inside a module and Which is nice here is that As a module developer I can create my view my views without having to think about How they will be hosted and what layout the host application will use so you can imagine that tomorrow I could create a new app with a different layout for different goal for instance and All the modules I've built rendering views will adapt to the layout that they will be hosted in So super flexible, but you could also say I want my custom layout or Take it dynamically for each application. It's up to you. In this case, we can reuse the layout which is So we can create controllers, but I could also create a razor page and just do add Older pages and then I will take this file and Call it about and convert it to a razor page that will Be routed to about and this is the about page If I run it again the module is built contains a razor page and the application should Expose it. Okay, and the same way here. We don't have any view which might be what you want so any layouts I could just add a layout section here and We use the layout from the host so that's the second thing we can add in MBC modules and the last thing I will show you is how do I add static content? So we create a folder called the debut Exactly the same way. I will build an ASP.net app and in this folder. I will put some kittens Can I find kittens? I have kittens So I put a kitten in my dub dub dub root and I assume it won't hurt it let's try to run it and The same way for controllers. We have a custom route to a custom convention to prevent Collisions we will do web API slash kittens dot jpeg and Then we can also serve static assets. So modules can serve all kinds of things and That's what is important in in this kind of modules because then it's really like a micro application a mini section of your site of your web app that you can put inside a class library and reuse it now the next step of Reusing a module is to Publishing it and to share it across different services or companies and Everywhere you want to to share it. So to do that we will use a new get package So ideally I will right click on the project and say pack which will create a new get package if I do that Visual studio will complain that the project cannot be packaged because packaging has been disabled So let's add this attribute this Tag to my project. I will add that tag and Also define a custom package version because I want to prevent Any conflict with previous attempts I did so I will give it a number and Just say pack and doing that I Have This file that has been created. So let's look at the folder Under web API been debug I Have the file just packed which contains my module and all the assets like the controllers The static files the kitten the razor pages the views and I will copy it inside this folder Which I configured in visual studio, let me show you I Configured this folder here. My new get packages is Pointing to local folder where I put my package. So it will be a new get package show So very interesting if you don't know this trick to check your packages and I can browse this Source and here. This is my package. So I will remove the reference from the project itself Okay, and let's run the application just to be sure that I Can't access the what my home. It's not available anymore because I don't reference the module anymore but I will install this package and Run it again So I just include my package as a new get reference and if I go to my home Then it's available again, and if I go to web API Kittens, it's also available Everything came from the package. I could put this package on new get or any other package repository and share it with everyone using your circle framework that's it for the Modularity and I think you can now Understand how easy it is to make modular apps Not mentioning that you could have apps that are made of tens hundreds of Different modules to build the main app you want Now let's go back to the slides Because I want to talk about multi tenant applications So multi tenant application is an application that will be deployed once but will be able to host As many or as much as you can as many Websites with a single deployment Typically, that's what we call software of the service when you deploy once but you can provision As many sites for each customers or as many services. So a single application can host multiple isolated websites a Very good example for that is what press dot com when you go to what press dot com you can create a new blog a new website you just type your name your email your Cree card information and you get a new site under either a prefix like Sebastian Ross block or a domain if you pay to own the domain and to register it on what press dot com But in terms of hosting What press didn't Install a new website somewhere They just add a new entry in their service to provide you with the same service But in isolation from the other customers So that's what is software as a service and that's what a multi tenant application is So how do you do that with a speeder net? Well, you will use orchard core. So and that's why We have modularity in orchard core to be able to provide software the service where every tenant Can have different sets of modules which are Which are deployed with your application So this is an example. I mentioned a tenant can be accessed through different domains Which we all point to the same servers But the server the application will route based on a domain or based on a prefix of Each customer to the set of data and configuration that the tenant represents Because each tenant is isolated meaning Each tenant has different services middleware and options in terms of a speeder net services middleware and options Each tenant can have different data like Configuration such as connection string or different data as in the database like different set of users even though it's It's provided by the same app and then you can isolate the tenants in terms of security for instance each Tenant will have its own authentication logic like let's use Integrated authentication or Google authentication and so on the cookies should not Cross the boundaries of the tenants and also maybe you want a tenant to have different features than the other like maybe I want a tenant to have my web API feature or my e-commerce feature or both of them based on what they want to pay for But I deploy once with all these modules and I can allow or disallow every feature for each tenant So how do you do that with? What you call well What you need to do is change this startup here to just Say at MVC and then let's enable multi-tenancy by doing with them and now I need to define somewhere What tenants I want to use and to do that. I have a file ready here. I will take that and Overwrite the one not this one. Yes. This is the one upset things replace So what's the difference in this file? I have a new section orchard call with three tenants my default tenant, which is the one that Was created before that I was showing you all the time and I want a tenant for my customer a and tenant for my customer b and inside this section What do I say is that this tenant is running because I could also disable every customer rich customer I could also say this is the domain that is mapped to this is the URL prefix that I want to use In this case my slash will be the default tenant These are the default features. I want my tenant to have so the default site won't have any feature And I can also add custom settings for each time like connection strings the color of the layout things like So if I look at my customer a it has a URL prefix Which will be the base path that I will have in the URL to target this customer a This is the same as if you use in what press that come your own thing and then here Customer b so if I run that First I will have to change the layouts one sec That's here my where application Pages shared. Okay replace Because I want a layout that works for everyone every Tenant, so I'm a default tenant, but if I do customer a I Also have a site or I need to rebuild it's just the asset. It doesn't it doesn't find so I can access the customer a or the customer b site I will build it works and you can see here the customer b has access to e-commerce and web API but commerce Customer a has only access to e-commerce So if I run it Have I do customer a slash e-commerce It works customer b slash e-commerce works also, but if I do weather forecast Which is coming from a different module customer b has it But customer a doesn't have it so I can customize every feature for each tenant and this is how you do multi-tenancy, you know to call this slide And that's the last demo I have So I encourage you to go and see our website watch a project net Our source code on the tub. We have also forums and documentations on my Twitter And if you want to see a real usage of multi-tenancy that looks like once present come We made a site that does exactly that it's a modular application Which is software as a service you type an email like my email you type a sign name and you choose what kind of website You want and this site will create a tenant inside itself and I Created one just before so you see it's tri-hotrod.net tri.hotrodproject.net and if I go Here I had I got a link right before it generated Your prefix randomly for you and now I have the site under the same domain and are currently hundreds of thousands of sites Tenants and they're the same deployment. So that's a good example of how you can reuse this multi-tenancy To make a software as a service application that will create tenants dynamically without any user interaction I'm ready Yes, so the default experience which is a service is to load the tenants from a file But in the example I just showed you the tenants are stored Inside of the file so in this case actually but Dynamically there will be saved outside of the app settings But a custom JSON document that will restore it and we have other providers that can store in Azure Blob Storage or the database That's the idea The next question so what happens if you have a module named the same as a controller action? There might be conflicts and That's why I also explain that if you find conflicts then you have to solve the conflicts and from your host application You can define the routing for the tenants. So actually here in add or trick or Or add MVC there is maybe add or trick or There is an extension maybe it's use I don't remember exactly where but there is an extension where you can add Custom endpoints from your host for different modules just to prevent any collision that could happen or try to make your modules Be all prefixed by the module name. That's Cool, so I'm just gonna hold the mic like this Only have the one All right, so I wonder if these modules can be deployed separately from the main application. Nope You can't with orchard core framework By design we didn't want to allow that because we tried it's very complex the issue being that if modules are dynamically loaded it might break your site and Also, it doesn't match with the The idea of deploying your set your service on different nodes Because you have when you install dynamically a module you will have to do that on all the nodes of your cloud And that's how to do because only one server will get the request to install a module. So Our suggestion is to test locally to build locally and then to deploy on every node We don't do dynamic loading of modules Alright next question. Um, what is the difference between a module and a project? I think some people were a little bit unclear on the terminology Okay, so the module is a geological concept which is represented by a project so a Project that references the modules target. We call it a module. That's a module is a project Okay, good to know and actually a module can contain multiple features So you can split inside a module which will be an assembly or package. You can split different features In the in the examples I gave right now. I just created a single feature default one I didn't create multiple features per module just to simplify the example But you could imagine a module that contains different logical sets of controllers views that you can enable and disable independently I think we'll have one last question before we switch over to our next speaker Is security handled from the orchestrator module or is it independent for each module? It's from the host application Permanent so each tenant will define its own security like its own authentication Its own authorization And you can have different ones So you could have it at the host level because it could be a middleware that acts before The Oracle middleware because at that point there will be a fork that will Map every tenant to its own set of middleware So every tenant can have their own set of middleware for security or you can have the middleware Define before watching so that you have a single Middleware pipeline to define the security All right. Well, thank you so much for joining us Sebastian. Next up. We have Robert Talking about cryptography 101 with.net core. So let's go ahead and call him on Skype Thank you so much for joining. Let's see if I can switch over to the