End-to-end walkthrough: How to Multi-tenant Application, register it with Azure AD, onboard tenants, go through the admin consent workflow, work with incremental [just-in-time] consent. All the code we write will be in C# and the application is an ASP.NET MVC application.
This is Step 7 of the series. To navigate to other articles in this series, look at the end of any article in the series for the list.
In the last episode we created a persisting token store, but we did not implement any mechanism to tie in the code to the actual data storage and retrieval mechanism. We said we would leverage my Azure Tables SDK to do that, but we did not do much beyond that. Let’s take that further and implement the storage and retrieval mechanism.
Instantiating and managing objects in memory at runtime is a fairly “expensive” task for the runtime and the host OS. The data access mechanism is an example of an object that will not change state at runtime. Our methods are self-contained and there is no overall “state awareness” except for the global-scope configuration — of where the tables are stored [aka the connection string].
What you need to implement an MVC service
An MVC “service” is nothing special. It is a class object. Period. What you do is, you place it into a special “hashtable” in the MVC system’s look up tables. When you need it back, you ask for it. Yes, this is as simple as using the ViewData dictionary from controllers/views. There are more complicated services that run asynchronously and stuff, but we will look at them much later.
You inject an object into this “hashtable” and ask for it back using interfaces.
Implement Azure Table Storage Service
So the first thing you need to do is declare an interface. Let’s do that. Create a new folder in the project (MvcServices, duh!), add a new item and select “Interface”. Now, there is absolutely nothing magic that you need to write in your interfaces or your implementation classes. Only, since we will be retrieving the object via its interface, we need to define our functionality in the interface or there would be no way to get at functions later on. The interface class for our first MVC Service is called IAzureTableStorageService. It contains just one function: GetDataSource.
Next, add a class file to the same (MvcServices) folder and call it AzureTablesService. Add a public constructor with an IConfiguration parameter. You get the IConfiguration via dependency injection [a piece of proper MVC voodoo] automatically at runtime. Use the IConfiguration object to get at the stored connection string from your appsettings.json file [or wherever you have stored global config — including environment] and save it into a class-scoped private field. We also build a ConcurrentDictionary to be able to look up already instantiated objects so that we can re-use as many objects as possible.
Finally it is time to implement our GetDataSource method. Note that we have defined a nullable Guid parameter to this function. But we are not using that yet, we will come back to it later. For now, simply return an instance of the AzureTablesDataSource object with the requested parameters:
- The first parameter is the connection string, get it from what you captured earlier in the constructor.
- The second parameter is the name of the particular table to connect to. The SDK provides a static function GetTableName to return this for you — it returns the value of the ‘[Table(“”)]‘ attribute on the “T” object.
We have written this function as the ConcurrentDictionary’s GetOrAdd() function, this lets us avoid complicated things like locking — which will be handled for us by the CLR.
The “service” itself is implemented now. Let’s plug it into MVC.
Open Startup.cs and in ConfigureServices method, scroll to the bottom where we added the IAzureAdTokenProvider singleton in the previous episode. Under that statement, plug in our latest MVC service using exactly the same syntax:
Remember to add the relevant “using” statements to the top of your file. Right-click on the squiggles and add it from the suggestion easily.
Now go into the AzureAd/AzureAdTokenProvider.cs class and add a using statement for our service. Scroll to the bottom where our constructor is, right-click on the squiggle under “IAzureTableStorageService” in the parameter and select the suggestion. You will see most of the errors vanish.
If you still see an error under the entire statement for the GetCacheKey method, you need to add the ClaimsPrincipalExtensions class [in AzureAd/ClaimsPrincipalExtensions.cs]. I forgot to check in that class in the previous check in. You will find it in the current codebase. Once you have this extension class, you will see the last remaining errors vanish.
If you have followed my code thus far, you should be able to now compile the project with zero errors and warnings :). If you get errors, do check against my checkin.