Converting a Monolithic Application into Microservices in ASP.NET Core (The process I follow)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone and welcome to dotnet code central in my last video i discussed about microservices in today's video what i'm going to do is i'm going to take a service which is monolithic in nature but not a huge one and try to break it down into multiple services and i'm going to take the example of a e-commerce website so i created this application which is right now it's a very simple application it has a home controller which is an mvc controller associated with the view which is the main view and then it has couple of web apis one is for inventory and another one is for product and then it has a data access component with multiple providers because right now it is plain and simple card application and then there are backing models for those data access components now if i run this application i see this page which is just currently showing for a particular user what are the products the user have part so products are apple and banana and the user mark bought 20 apples and 10 banana consider it's more like the user's home page now apart from that what we have is inventory rest endpoint and as you can see the inventory has name of the products and what are the quantities apart from inventory we have product which has the name description and type of the product so it's a very simple example but when we are starting an application like this i would start exactly the way it is right now which is three or four controllers and i would probably not use an mvc i would probably use a web page built either using angularjs or some other web framework and then i'll have just rest endpoints to provide all the data needed at this point in time it is pretty simple but let's consider some of the aspects which are not right currently with this application for example if we need to change inventory or product or any one aspect of this application the entire application needs to be tested because they are all part of the same deployable unit irrespective of what got changed technically anything could be impacted so from a testing point of view the entire deployment unit needs to be tested so we have to have a regression test for everything and of course functional test only for the features that are changed which makes the cost of testing higher so that's one aspect the second thing is about the scaling aspect for example the product search which is search of a particular product is going to be way more higher than showing an order for example this particular api will be called not necessarily product it's mainly the inventory because inventory has the product as well as the quantity and that's what the users would be interested in seeing it's going to be way higher than just this order page because whenever user come in they're going to search for products they're going to go through multiple products and then they're going to buy and after that when they go to history they'll see what their order histories are similarly on the customer care side the call for looking into order is going to be much lesser compared to issue with the product so when the aspects of scaling now as you can understand the scaling for product is completely different than what is the scaling for order they have complete different scaling requirement now if everything is in same solution or same deployable unit the same project has to be scale respective of what part of the project is called more versus less and that creates little bit of inefficiency having said that at this point in time if i have to break out this application i'm just going to take the order aspect of this application out into a single responsibility service or a micro service and keep the inventory and product controllers in this project itself that would be my first steps towards doing this why i would do that because the order is pretty isolated so if i get into the database for this application right now i created very simple four or five tables so let me show you all of them so here as you can see i have couple of products and then i have an inventory now the inventory did not need a name but i kept it for the timing and then i have a user and this is the order the user made and these are the order details for this user what product and what quantity so that's what i have now as you can see here i can easily move the order and order detail out of this application user can still remain in this application because user id can be passed along to the service to figure out what the order is both for setting as well as getting the order so that would be the first step for me in breaking out this monolithic application into microservices or single responsibility services and in my first step i will keep the tables in this database itself as i mentioned in my earlier video i will not go immediately to break the database also because there are cost associated to it so on day one i would just keep the tables in the same database though i would ensure that i don't have multi-service stable access because that's going to create a problem so now to do that i'm going to create asp.net core web application and this time i'm just going to create a web api so here i can say order service which is just responsible for order and then i'm going to go with the api application i'm going to keep everything as this now here we can just go with the docker support so that it can run in a container and once we create this application you can see that the docker file is also created so now what we can do is in the controller first let's get rid of the weather forecast controller because we don't need it similarly let's get rid of the weather forecast class now next thing what i can do is i can just create a controller and i'm going to create a api read right controller and it is going to be order controller so now what i can do is i can also create a data access class here now since it is a single responsibility service we don't have to create multiple folders we can just add classes directly to this project itself because we are not going to have a lot of classes but in this case instead of creating a new class i'm just going to copy the existing classes from the e-commerce project so i'm just going to copy the order detail provider it's interface as well as the class and here i'm going to change the namespace and the next thing i'm going to do is i'm going to copy over the order detail model also so now i copied the order details model so once i'm done with that what i can do is i can just change the namespace of all the classes to current one and then this error should go away but what i have to do is i still have to add the sql connection as well as the dapper reference so here i'm using dapper if you are not familiar with pepper i have a couple of videos on how to use dapper you can take a look into that i'm going to provide a link in the description as well as in the video here we can go and search for dapper install and then for sql client we can just find the latest version and install it i had to add the default namespace also now once we have these two the next thing we need is adding the connection string into the config file so we're just going to do that we're just going to copy and paste it from this solution and once that is done we're going to go into startup and add these newly created class into the dependency injection container and we're going to provide the name of the connection string which is just connection string so now in the dependencies container we injected the order details so from the order controller what we can do now we can create a constructor and the constructor we can inject this newly created interface and then here instead of these we can say order detail and right now since we are returning all the order details so just for the simplicity of the application i'm just going to return everything so now i'm going to run this application i'm just going to run this application in a console mode because it's easier you can run it docker also the docker file is there so i'm just going to run this application now once i run this application it's running in port 5001. the weather forecast does not exist because i deleted it i can just say api and order if i do that i can see the same response as the one available here so i can now practically point this ui to call this service and then get rid of the i product detail provider from here that will break out one service so that's one example and as you can see here we can keep everything same and here in the order details provider instead of making a call like this we can just make an http call and call the service which is running on the port 5001. let's just do that so we can get rid of this we don't need connection string what we can do is let's have the constructor and here let's use http client factory and then from the http client factory we can do equal to http clientfactory.createclient and we can name the client as order so let's configure the client factory here so that we don't forget so here we can go so we can say services dot add http client and we can give the same name as order that's the name we gave here so we have to keep the same name and then here for configuration we can just pass the base address so we can say config dot base address is equal to new of uri and we can pass the uri of the application which is this and then when we go back here we can say client dot get async and in the request uri we can pass the rest of the path which is api slash order and here we can say var response equal to so we have to make this as async and this will be a task of the order array instead of just order array we'll have to change the contract of the interface as well and that'll of course change everything at the controller level as well so we have that and then here we can say for data is equal to again await response dot content dot read as string async so this will read the cons content as a sync and after that we can do json json convert dot let's add newtonsoft it's not there and we can say deserialize object and we can pass order detail array and here we can say data is the item to deserialize and we can just return so this would return and we don't need the dapper or sql connection anymore so we just all we did is we kept everything else the same but now the order details provider is just making an http call so that way there is extremely less change in this monolith meaning its view doesn't have to significantly change all we did is we moved the order into a different microservice and we are just calling it through an http call now here is an extremely important thing to remember when we are building microservices we have to think about resiliency from the get-go so i have a video on poly i actually have couple of videos on pauli so you can look into them about how to manage circuit breaker as well as auto retries but here the important aspect i want to share is one thing you have to remember is in case of any exception what is the user behavior how do you want to behave that's very critical so couple of things to keep in mind is that if the service fails maybe you don't fail maybe you just written empty array so that the user can retry later and your application is not broken so in this case what we can do is we can create a try catch block and we can have this code inside of tricatch block and on exception we should be able to just log the exception and for logging we can use a i logger so we can just say i logger of order detail provider logger and then here we can just say logger dot log error the exception and then after that we can just do return and we can return an empty array of order details so this will ensure that there is no null reference exception and your page is going to still load it's just that it's not going to return any data so on the client side you can have a check or to show an empty result set the other thing you can do is from here instead of throwing an error or something you can just return a error response object and based on that error response object you can show the user a message that the data is not available right now try again later so there are multiple options you can choose and it totally depends on the requirement of the application for the time being for simplicity and so that i don't have to spend a lot of time writing those extra models i'm just returning an empty array so now if i run this application ideally it'll still hit this same order service here and i can put a breakpoint and then it'll get the data from this order service so i'll get a breakpoint here also since the contract now change in the home controller the cat is an away table so ideally this should be async and we can use the await here to have a task let me add the task and here the order provider doesn't take anything so it takes the i http client factory but i don't have to pass it because it's part of the dependency injection container itself so i can just configure it this way now if we run you can see it came to the order controller so order controller is going to return and then it's going to come here it's going to read a sync and then it's going to return the array back and here you can see it has printed the exact same data as before in the ui so this is a very simple demonstration of how you can break out a particular part of a monolithic application into its own micro service now your order service is not complete because you need to have post method get method another thing but it clearly shows how you can isolate a particular functionality into a complete different service and how you can retrofit the feature into a ui based or aggregate application here all we did is we changed the order detail provider to instead of going to a database to make a http call now you might be asking like why we are doing this is not it too much well in this case because the application i'm showing is very small it feels like it's an overkill that's why i mentioned before if your application is small don't think about microservice go with the single monolithic application it will work but when your application get complex that's when you have to think about microservice for example if your order had a lot of other features which i have not added like posting an order updating an order managing the order then it becomes critical that you put order into a different service because any change to order now the entire application needs to be tested and at that point in time it's an overhead the other thing is let's say now we have separated the order and now we have inventory and product into the same controller and which works for the current situation but let's consider the situation that now we have to add a warehouse into the miss meaning so far you had only one warehouse but due to the expansion of the business now you have multiple warehouses so now you have to consider that you have a concept of warehouse now if we have to add a warehouse here what is going to happen is now the warehouse is going to have a id of the inventory and that's what will contain the count so let's do that so i'm just going to add a new table which will have id it's going to be integer and i'm going to keep it as auto increment so i need a specification yes and then is the name of the warehouse and then finally warehouse of course needs address and other thing i'm not going to add them for the time being the only other thing it will have is inventory id which is an integer so and we can name it as warehouse so now the complexity that is going to happen is the inventory provider cannot just go ahead and return the inventory as is it has to now join with the warehouse and based on all the warehouse it has to figure out the inventory so you can see how adding a single table now is going to make a little bit of complexity here right it introduces complexity now only inventory is getting changed or the future of inventory is getting changed but your product also needs to be tested so this would be a situation where you would say okay let's now break out inventory into its own micro service because warehouse and inventory are clubbed together maybe i can start with breaking them out keep them into a single micro service and move on you can break out warehouse and inventory into a single micro service and name it as inventory so that's a good start but if inventory and warehouse also starts becoming really complex because they are two distinct functionality that's when you can break them up into an inventory and a warehouse micro service so this is how you should be thinking about it at least this is how i think about how i break micro services another thing is in the order service right now if you look into that we are joining with product so we are still accessing the product database so this is something has to go away so there are two solutions to this now we don't need the product here if we remove product what is that we are going to miss we are going to miss the name of the product so now there are a couple of things you can do one thing is you can call the product service from here or the other option is you can go ahead and update your order detail table and in the order detail table you can add a new column and you can put it as name instead of name let's put it at product name which is the name of the product and i'm going to save so now the product name can be part of the order details so when our order is added we can add the product detail also so now here i can just go ahead and update for simplicity wrong table and here i can say so now what happens is in our code here we can still go ahead and we can say order detail dot name product name and then we have the user also we are getting the user id from the user table so we need to get rid of that as well so the next thing we can do is we can go to order detail either we can add this or technically in a real life scenario we don't have to because the user information should anyway be part of some sort of single sign-on solution which passes across different services now order already have a user id so it notes about the user so for the time being in the order table i'm just going to add a username and then i can edit and add the username here so now if i go back to my application i have name as user and i don't need that i can just say username as user that's what we added let me again select so we have username id and updated time so we can just say username from order and order detail dot product name order dot quantity from order join order detail and then i can just delete the join with user so that's all we had to do so now what happens is i have completely isolated the order service which is now using only this order and order detail table and this is the time when now i can break this to table and get them into their own database and that database can be a cloud native database so that cost is much more smaller because you are dealing with only two tables in a real life solution the order will be much more complex and it will not be limited to these two tables in which case it will be justified to use some sort of open source database solution like postgres which i use heavily so now if i run this application again it should work exactly the way it was working before and you can see it is giving my name is not showing up because i probably made a mistake in the query yes name because that's the property okay let me run again now if i go you can see that the user the name and quantity everything is showing as expected and if we go back to this page and refresh it should also work as expected so nothing changed so this is how you can isolate the database first move the service as is then go back to the parent service and change the database call into an api call and then come back in the service and refactor so that you don't have any database dependency with the monolithic service and once that is achieved you can break out those tables which are necessary only for your service and move them into a different micro service now here the path that i took for both order and order details is i added couple of columns because it was just one attribute so it makes sense just adding the data redundancy it's not an issue or it's not a concern when you go with microservice because microservices are supposed to contain their data in their own context so the name of a product and the name of a user is in the context of this microservice and it can keep these two but if you are going beyond name and you are going with other attributes like you know product sku number product manufacturer and all other attributes of a product then the order service should be making a call to product service to get all the information for the product that is the boundary you have to understand and you have to draw at least that is what i do is use the attributes the common minimum attributes which makes sense keeping in the boundary or in the context of a service and anything which does not make sense but we still need to show it as a part of this service then i'm going to make a call to the parent service to get the data now in some cases so if we consider the example of this case where the order controller just returns the common minimum aspects of an order but our application here which is a web-based application needs more information about the product at this point in time this application can directly go into the product service to fetch those data and do a join between the order detail and the product and give user the details information they want that's how i would try to break the service so as you have seen first i figured out which is the minimum service which can be easily taken out from this application and i moved this rest endpoint into its own service and after that i came back to the parent service and changed all the db access point into making http call and then after that i went into the microservice that i created and got rid of all database dependency with the parent monolith and made sure it is accessing its own table only and after that is done those tables can be completely taken out of the monolithics database and put it into own database for the microservice and this is the process which you can repeat again and again until unless you break out your monolith into multiple micro services but again break out the monolith only if there is a need if you see that it is not working out for you for me the requirement for breaking a service into multiple microservices is the deployment need i decide based on am i able to move fast enough am i agile enough and also can i give this service to anyone coming to my team and can they pick it up within a day or two days not in months that's the criteria i look at that's why i tend to keep the services small it makes transition of service really really easy and simple but that might not be the requirement for you so you have to look into what makes sense for you to break a service into microservices that's all i wanted to cover today again i have not covered all the aspect of micro service but this is a start if you have any questions if you want to know more about it please leave a comment and if i'm not able to answer all the questions through the comment then i would create another video next week to cover all the questions from the comment section if you are new to my channel and if you think you are getting value out of my channel please subscribe to my channel and thanks so much for watching this video
Info
Channel: DotNet Core Central
Views: 8,747
Rating: undefined out of 5
Keywords: microservice, asp.net core, .net core, monolith to microservice, break monolith to microservice, microservice in aso.net core, microservice in .net core
Id: 3AKqtggkaIA
Channel Id: undefined
Length: 28min 49sec (1729 seconds)
Published: Sun Sep 06 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.