OPTIONS PATTERN in ASP.NET Core | Getting Started With ASP.NET Core Series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
when building applications it often needs access to different configuration be it a connection string a client id or a secret an external api url and a token etc by keeping these values in the applications configuration we can use different values in different environments asp.net core provides a rich support for adding various configuration sources including the app settings the environment variables keyword and many more we learned how to integrate with these different sources in a different video about configuration which is linked here and in the description below in this video let's learn how to consume these configurations from the application code you write using the options pattern in asp.net core hello everyone my name is rahul and welcome back to my youtube channel in case you are new here and want to know more about me check out my blog which will be linked here i recently started a newsletter which you can subscribe while you're on the site and please don't forget to subscribe and help me grow this youtube channel let's head off to the console and create a new.net web api application i'll use the.net cli and use the new and the web api to create a new template this will create a new application in the current folder let's open this in an ide of your choice i will use rider for this example since i have linked it with my command line i can use rider 64 and dot on this folder this will open the newly created project in rider by specifying dot it will open up the current folder and the associated projects in rider here i have the web api template opened up in rider and it has a program.cs the startup.cs and a default controller which is the weather forecast controller this controller currently hard codes the data which is getting returned on the get call let's modify this code to talk to an external api let's clean up this class to start with so let's remove this hard coded data and also this method that returns the dummy data back let's take in a city name which is where we are going to expose the values and give it a default value and let's say brisbane which is the current city that i am right now in instead of returning an i enumerable of weather forecast let's simply return a task of screen which will be the json response from the external web api to talk to an external api let's inject an i http client factory to create an http client so let's name this http client factory and make sure to create a read-only field in this class i have some code already written out to talk to the external api so let me paste that in here and walk you through it i have the external api url which is the api.weatherapi.com it uses a secret key to talk to the api and also passes in the city name which is a queue parameter in the api url this city name is currently coming in as a parameter to our api method we use the http client factory to create a new client and we have wrapped it in a using statement let's make sure to add a sync in here so that this await call returns as expected to learn more about how to use an http client and what the good practices around it are check out my video on that linked here or in the description below using the http client factory is just the starting process in that but i'll stick to that to keep this simple to make sure the i http client factory gets injected into our controller let's go to the startup.cs class and add in the support for that under the configure services method we can register in the dependencies that this application needs so here we can say services dot add http client this will register for the http client factory let's run this application and make sure it works as expected the application is running as expected and it returns back a string json which is the weather for the default country that we gave brisbane we can pass in additional properties in here but let's keep it like this for now let's refactor this code to extract this url into an application configuration to start with let's extract this part as a base url so let's name this as base url and given the value that we just copied which is the value to the url to the api since i have the string interpolation already here let's use the base url to specify that value now this key definitely can also go into a configuration so let's copy that and name this as key so let's give that that value and make sure to use this inside the url that we are constructing so let's keep it in the appropriate place and call this key now we have this url getting constructed of a base url the key and the city name which is coming from the api parameter we can now extract these two values the base url and the key to the application's configuration so let's open up the explorer and go to appsettings.json in here let's add in a new section for the weather api so let's specify weather api and give that as an object in this case it's going to have the url as a property and also the key which is going to be the api key so let's go back and copy these two values from here so let's copy that from here and put this into the url similarly for the key so let's use that and specify it in the key part now we have extracted these two values into the applications configuration the easiest way to consume this config is to use the i configuration interface if we go to the startup.cs class you can see an eye configuration getting injected into the constructor similarly we can inject this into the weather forecast controller as well so let's go back to the weather forecast controller after i http client factory we can inject in an instance of the eye configuration let's add in the relevant usings and name this configuration to use this let's make sure to have a read-only field and starting use the i configuration to get the values from the config let's now use the configuration to retrieve value from the configuration source in this case the appsettings.json file to get a value we can use the underscore configuration and use the getvalue method in that since we know that it's a string let's specify it as string for the key let's use this section value and specify a colon to separate the hierarchy so it will be weather api colon url similarly for the key let's use weather api colon key so this is going to retrieve the value from the configuration interface that gets injected into the controller let's run this application and make sure it's working fine as expected the application is running fine as before and we get back the json value for the city brisbane the api key in here which we have specified in the appsettings.json is a sensitive information normally i wouldn't put that in the appsettings.config as a plain text a better place would be to use keyword which i have covered in a separate video for this video to keep things simple let's leave it in here and move on injecting in the eye configuration into the controller is a bad design pattern it is very similar to the server's locator pattern which is often considered as an anti-pattern looking from the outside there's no way to tell what configuration values that this controller now depends on all it takes is an interface f i configuration which has all the config values inside of it and also the controller class is now tightly coupled to the way the config object is structured it needs to know that there is a weather api section it has to use a colon to separate for hierarchy and also specify the properties that's required for the url and the key so this controller is now tightly coupled with the configuration and the way it is structured let's see how we can fix this using the options pattern available as part of asp.net core the options pattern is an extension on top of the i-service collection and provides a way to access group of related settings it uses strongly typed classes to represent config values let's see this in action to start with let's create a new class to represent the config values for the weather api let's name this weather api options i'm using options here just for conventional purposes you can name this as you want we have two properties the url which is of type string and also a key which is also of type string so let's create those two properties inside of here for the section name in the config we can choose to keep it here so that we don't have to hardcode it anywhere else so let's create a constant string and call it weather api so this is equal to the section that's there in the appsettings.json which is again weather api so let's specify that along with the options as well to start using this newly created class in the weather forecast controller let's inject in and i options of the new class that we just created in this case weather api options so we can name this as weather options make sure to include the relevant usings which is the microsoft extensions dot options in this case let's save the weather options to a private field so let's specify underscore weather options and given the weather options dot value which is of type weather api options so let's save that create this new field weather api options and start using that inside our controller class so instead of underscore base url getting from the configuration value we can use underscore weather options and specify the url from here and also in here instead of the key from the configuration let's use the weatheroptions.key so now we have both the values getting injected in using the options pattern to dependency inject the weather api options using the options pattern let's use the services and specify the configure method here we need to specify a type which is the weather api options since this value is coming from the configuration let's use the injected in i configuration instance to retrieve that value so specifying configuration dot get section so we have the section name inside our weather api options class so let's use that to retrieve that particular section in this case the weather api so this is going to read the values from the section weather api from the appsettings.json file and register it as an eye options of this particular class let's run this application to make sure it's working fine as expected the application is running successfully and it returns us back the data for brisbane as we have specified an options class must be non-abstract it should have a public default constructor all the public read write properties are bound to the configuration value and the field values does not get bound like the weather api string that we added in the class applications that we write often talk to multiple services including a database an external api like in this case an authentication service etc which all needs different forms of configuration values it's a good practice generally to keep these settings grouped and separate from each other which means we will have several different classes like the weather api options that we just created now by doing this the app adheres to two important software design principles the interface segregation principle which means the classes that depend on the configuration settings depend only on the settings that they use and also separation of concerns which means the different parts of the app does not use the same configuration and are not coupled with each other everything is working fine but let's say we need to update the api key of this weather api so let's head off to the weather api dashboard i have used the weatherapi.com api for this example so let me regenerate this key so let's say i agree and regenerate the key so i have a new key so let me copy that and update the appsettings.config we still have the application running but let me update the app settings right away and save this let's come back to the api and make a new request to make sure the request doesn't get specified from a cache let's specify a city name so in this case let's give in london this request now fails with a 401 unauthorized this is because we have changed the api key however the application did not pick this up even though we updated the appsettings.json to get this to working for now i'll have to restart the application so that the app settings will again be refreshed i definitely don't want to restart the application to update the api key so let's see how we can fix that the options pattern supports multiple interfaces in the weather forecast controller we used the i options interface as you can see the i options interface does not support reading the configuration data after the app has started it is registered as a singleton instance which means once the application starts it's going to have the same value even if we update the values in the configuration if we want the values to be recomputed on each request what we need to use is the i options snapshot in this case the options value is recomputed on every request it is registered as a scoped interface which means we cannot use this from a singleton service however in our case the weather forecast controller is not a singleton service so let's see if we can use the i options snapshot let's go back to the weather forecast controller and instead of injecting the eye options let's inject in the i options snapshot it has a value property on that interface as well so the rest of the code works as expected let's run this to make sure it works as we want the application is running and it is getting back the value as expected let's go into the dashboard again and regenerate this key as before it has created a new key for us so let's copy this value before updating the value in the app settings let's go back to the api and make sure a request fails so let's specify a city name and specify in this case sydney to make sure it doesn't get served from the cache since the api keys are now updated it returns an unauthorized so let's go back to the application settings and update this value in here which is the new api key that we just regenerated so let's save this this should trigger an automatic reload from the next request so let's go back and refresh the request to sydney now you can see the application is working as expected i did not have to restart the application to have the changes to the app settings reflected this is because we use the i options snapshot note that the i options snapshot works only with configuration sources that allows reloading of the data if we navigate to the program.cs class we can see the host.create default builder this is where the appsettings.json is getting registered if we go into the definition of this method and scroll down we can see the adjacent file request to the appsettings.json file we can also see that this is specified to be reload on change this is why the configuration values is getting updated anytime we make a change in the config file so if you are depending on the i options snapshot make sure the configuration source that you use also supports reloading on change with the options pattern we are binding a strongly typed classes with the values in the json file a lot of things can go wrong with this let's see a few examples to start with if the section name that we specify in here does not match with the values in the appsettings.json let's see what will happen so we have the application still running so let's make a change in here to add a typo so let me add an extra i and go back to the application and refresh it since we are using i options snapshot it will reload this new section for the new request so let's refresh this and here we see that the uri is invalid and the base uri address must be set let's add a breakpoint to the weather forecast controller to see what is happening let's go back and refresh this request again and here we can see the weather api options is now returning null values for both the key and the url this is because it does not find a matching section in the appsettings.config similarly let's fix this api section if one of the values is wrong let's say the url has a typo and if you refresh this request this is going to be the same so in here the weather api options successfully binds to the key property however the url is still null so any mismatch with the sections or the property names gives it a default value the options class can also have types other than string so let's stop this application go back to the weather api options let's add a new integer property let's call this count for example go back to the app settings.json file and add in a new value for count so let's specify 12. let's make sure to fix the url property and run this application to make sure it's working as expected the application is running and it makes a new request to this api endpoint here we can see that we have the count property getting applied correctly so it's automatically binding the type to an integer property in here if this type had an invalid value let's say we give it as invalid which is definitely not an integer so let's save this and make a request again this now throws an exception so when it's trying to create a weather api options and try to convert the count property to integer it says it cannot convert it and that the input string was not in the correct format let's revert this back to a valid value in this case 12. we can also add validation attributes to the weather api options so if we want to specify that this url is required we can use values from the data annotations library so let's specify required which is getting imported from the systems.component model dot data annotations we can specify the same for key as well we can also use the other classes from the annotation libraries like range which specifies a range of values that this property can take so let's say it can be anywhere between 10 and 100 for example to enable this data annotations library we need to come back to the startup.cs and slightly change the way we configure the api options we can use the services dot add options method so this also takes in a type so here we can say weather api options let's bind this value first to the configuration section so let's use bind and specify the configuration dot get section as before and also specify the weather api options dot weather api to enable the data annotations that we added on the class let's specify the validate data annotations method so this is going to make sure those annotations are getting evaluated let's run this and make sure everything is working as expected the application is running and it returns back all the value as expected let's go back into the appsettings.json and now let's say if we have a typo in here for the url property and save this and run this again it's now going to throw an error it says the url field is required this is because of the data annotations property so it's no longer making a request to the external api and saying it is an invalid url it explicitly says even before saying that this property is required let's fix that back and give a count which is a ls value let's say 1 and if we had specified it to be a range between 10 and 100. so let's run this again and this is going to now say that the count must be between 10 and 100. you can also use other data annotation attributes including regular expressions to validate these properties for more complex validations you can use an i validate options interface and write your own custom validations check the description for the link to the documentation i hope this helps you to understand more about the options pattern in asp.net core and how to use it to get configuration values in your application code the options pattern helps to keep the code clean and well separated it also supports additional features like automatically reloading of the configuration values as and when they change if you like this video please make sure to hit the like button and if you want to be notified in the future of similar such videos please make sure to hit subscribe thank you and see you soon
Info
Channel: Rahul Nath
Views: 5,308
Rating: undefined out of 5
Keywords: ioptions .net core, ioptions vs iconfiguration, ioptionssnapshot not working, IOptionsSnapshot asp.net core, asp.net core options pattern, options pattern in asp.net core, using configuration values in asp.net core, how to use configuration in asp.net core, ioptions vs ioptionssnapshot vs ioptionsmonitor, IOptions vs IoptionsSnapshot, dotnet core options pattern, .net core options pattern
Id: SizJCLcjbOA
Channel Id: undefined
Length: 21min 7sec (1267 seconds)
Published: Thu Nov 05 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.