3.4 Build a Custom Configuration
There are a few things hard-coded in our app that shouldn't be. We'll fix that in this lesson, and we'll fix a few cosmetic issues with the code.
1.Introduction1 lesson, 01:40
2.Get Started2 lessons, 11:54
2.1What You Need05:38
2.2How GitHub Webhooks Work06:16
3.Build the App4 lessons, 56:39
3.1Start the Project11:06
3.2Secure Our Webhook15:21
3.4Build a Custom Configuration12:59
4.Display Content3 lessons, 38:55
4.1Parse the Documents10:21
4.2Display a List of Posts14:54
5.Conclusion1 lesson, 01:10
3.4 Build a Custom Configuration
In the previous lesson we wrote the code that will process the requests from GitHub. But we didn't test that code, and we will in this lesson. But before we do that, there are a few things that we need to do. The first thing we need is to put all of the things that should be in the configuration in the configuration. By that I mean our base URL for downloading our files, and then inside of the GithubValidate class, we have our SecretKey, the "ducks fly with geese". These are things that should be in our app settings. Now in ASP.NET 5, the configuration for our application is vastly different from prior versions ASP.NET. Instead of a web.config file, we have several JSON files. And what used to be the App Settings section in web.config is now this appsettings.json. And you can see we have kind of the same type of information, although now we have these connection strings that are in here as opposed to a section inside of our project.json file. But we can come in here and we can add our own setting. So we can have GithubPush, and then we can have some properties for this object. The first could be our SecretKey, and we know that that is "ducks fly with geese". So we can set that there. And then we can also have the BaseDownloadUrl. And we can go to our GithubPushProcessor and grab that URL as the value for this property. So we have our settings now, but we need some way to access them. And it would be nice to be able to just have a class that's called GithubPush that has properties of SecretKey and BaseDownloadUrl. Now we have to write that class. So let's go to our Solution Explorer, and I'm going to add a new folder called Config, or yeah, config, that'll be fine. And then inside of this folder we're going to have the GithubPush class. We're going to have two properties. The first is SecretKey. The second is BaseDownloadUrl. But by default it's not going to automatically map those settings to this class. We, of course, have to tell it to do that. So we need to go to our Startup.cs file. And we need to go to the ConfigureServices method, because this is where we can tell our configuration that hey, we have this new section that we want you to parse and it needs to map to that GithubPush class. So here we say services.Configure, and this is a generic method. We use the type parameter as our GithubPush class. We need a using statement now for our config name space. And then whenever we call this method, we pass in Configuration.GetSection and then we specify the section "GithubPush". Although, you know, let's go ahead and let's change the name of the class. Let's go back and instead of just GithubPush, let's do GithubPushConfig. And we will let Visual Studio rename that class and all of the usages of that class as well. Now we can retrieve the configuration using MVC's dependency injection feature. So we can go back to our controller. Let's add a private readonly field of type GithubPushConfig. We need a using statement for our config name space, and let's just call it _config. Now we can't just come to our constructor and add another parameter of GithubPushConfig because the IOC container doesn't know what that type is. Instead, we have to use a type called IOptions. This is a generic interface and it's in Microsoft.Extensions.OptionsModel, so we need a using statement there. And then the type parameter there is GithubPushConfig, and we'll just call that options. And then we can set _config = options.Value. So now we have our config. And we can pass that to whatever needs the configuration, like our GithubPushProcessors. So in addition to the WebRootPath we are going to pass in the config. So we need to go that constructor and add that first, so let's add the field. So let's make this readonly GithubPushConfig. And once again, we need that using statement, and we will call it _config here as well. And we need that parameter to the constructor, we'll call that config. And inside of the constructor we'll set _config simply to config. And then, finally, inside of the ProcessAsync method we no longer want our hard-coded URL. Instead we will say _config.BaseDownloadUrl. So there's one place that we have soft-coded our app. Now we need to go the validation, and this is GithubValidate. Now things are going to be a little different here because this was set up as a static method. So what we can do instead is just pass the secret as a parameter. So we have our signature, then we can have the secret, and then the requestBody. That will simplify that somewhat. And then back inside of our controller, we pass in the header and then _config.SecretKey and then the body. Before we do anything else, we need to test the code from the previous lesson as well as what we just wrote. So let's fire up Fiddler and then we will execute our application. And hopefully everything Is going to work just fine. So once we see something in Edge, then we can head over to Fiddler and execute a request. So there it is. Let's filter out this process so that we're not flooded. And over here in the composer you can see that it keeps a history of all of the requests. So just double-click the top one because that's the last one that was made, execute, and uh-oh, we have an error, Error 500. So double-click on that and let's go to text view. We will scroll down to see what the error is, and here it is. There is an authentication exception. The remote certificate is invalid according to the validation procedure. Okay, that's probably due to Fiddler and how I have everything configured. So you might get this or you might not. It just really depends. If you do, then you will want to go to Fiddler options and uncheck Capture HTTPS CONNECTs. So now that that is done, let's go back to the composer and we will execute that request again. And voila, it worked. We see that we have a result of 200. Now that just means that we didn't get an exception. Let's go to our Solution Explorer. Let's go to wwwroot, and there is the posts folder. So it did download those files and there they are. So we can open up those. There's really nothing of importance in them, and there we go. So our code for downloading and saving those files works. Now let's check to see if updating them works as well. Now we're not going to really know except if everything goes okay. So if we get an exception, then of course, yeah, we need to fix something. But we don't, so everything seems to be okay. Let's make sure that it just overwrote those and it didn't append them, and that is the case. Okay, so the code from the previous lesson is good to go, as well as the code for our configuration. Now let's just clean this up a little bit. Now the reason why I want to clean this up is because as I have mentioned before, I like lean controllers, and even though this controller is really only doing one thing right now, I still want to make this method as small as possible. So instead of having all of this here, it would be nice if we could do something like this. var payload = await, and then we would use an extension method for Request, and we could call it GetGithubPayload. And then we would need to pass the SecretKey because it needs that. Well, we need to call this Async. So we could call this if we have a payload then we want to process. Otherwise we would do what we did before and set the status code equal to 400. So if payload is null, then we do this. Otherwise we process. So it saves a few lines of code, but it's also easier to read in my opinion. So we are going to create this extension method. Let's got to our Solution Explorer. Let's at the roots of our project add a new class called RequestExtensions. We need to make this a static class and then we need that method, public static async. And this returns a Task of whatever type is our payload, and I forget what it is. So let's go to Models > Github and it's PushPayload. So PushPayload, we need the using statement there for that namespace, and we called it GetGithub, that's hard to say, PayloadAsync. Now since this is an extension method for the request, we need this HttpRequest, and we will just call that parameter request. We need a using statement for Microsoft.AspNet.Http. We also need the secretKey. And then I will paste that code in here. Now instead of the uppercase requests, we'll have a lowercase request and we will replace all of those. We no longer have Config. Instead we just have the secretKey. We need a using statement for GithubValidate and a using statement for Newtonsoft.Json as well. And really that's all that we need to do. And since this is asynchronous, we can also await this and use the Async version there. And yeah. Although what's this green squiggly? Asynchronously deserializes the JSON to the specified .NET type. Deserialization will happen on a new thread. I don't want a new thread. Let's just do that. That would be fast anyway, so we'll just do that synchronously. And then if the validation fails, then we want to return null. Otherwise we will return the payload. And that's really all that we need to do. So we now have a slightly leaner controller. But with everything let's test to make sure that these changes are going to work okay. And then we can call at least this lesson done. So we still have Fiddler going. Let's clear this out. Let's Execute the request. And we get a result of 200. Once again, if we look at the wwwroot folder, we still have posts. We still have those files and everything is working okay. So now we have just about everything that we need. We have code that is processing the requests and saving those files. But the idea behind this is that we would be using actually markdown files. So we need something that will convert markdown into HTML. We also might need to parse some special things about those markdown files as well, like if there's any front matter or anything like that. So we will get started with that in the next lesson.