Introduction
It's since log time I wrote something on a community web site. This statement doesn't mean that I was a regular writer before. But I used to scribble down interesting stuff I learned to better solidify what I learned, as well as to learn more from the comments I got on those write-ups.
This time I am going to put up some details about ASP.NET Web API. I know there are tons of articles available on this topic, but still, I want to write something simple about constructing a simple Web API.
Intention
To develop a Web API for organizing a Pot Luck event using:
- ASP.NET Web API.
- Dependency injection using Strecturemap IoC container.
- Entity Framework 6.
- Repository Pattern&
- Web API Help and Simple Test NuGet.
When you finish reading the very last line of this article, you should be able to develop your own Web API with above mentioned items.
What is Pot Luck?
(Don't waste your time here: https://github.com/kuttikrishnankodoth/PotLuck/archive/master.zip). Just a simple case study, not as elegant as NerdDinner :)
For those who don't know, pot luck is a get together event with food, organized by friends or a group of people. Each individual will bring food instead one single person cooking or buying food for everyone and the food will be shared among the people. This way, everybody will get an opportunity to taste different cuisines.
Organizing a pot luck event is a little tedious, and includes things like coordinating with people and selecting the cuisines each person brings, or splitting up any extra overhead, etc. You will get to know more about this on the fly.
How am I Going to Proceed
I'll start without any of the fancy stuff mentioned above, but as we progress I'll use it more.
Let's Start
My plan is to start from scratch so that a new comer to Web API can also use this. So please skip this section if you are already aware of the basics of setting up a project.
I'll be using Git as my source repository. If somebody is planning to develop some project with a team of less than five or so the Git and TFS are available for free in Visual SWtudio. Also I'll be using Visual Studio 2013 Community Edition instead of Web Express or other paid versions. First thing's first, let's set up a Visual Studio solution by adding an empty Web API project in that.
As the next step, select an empty Web API project template as shown below and make sure you only checked the Web API check box. Anyway, I am not going to add any Unit test project now. We can add that once we complete the development of at least one end point (action method).
Upon clicking the ok button you can see a wonderful project got created in your Solution explorer with the below folder structure.
So now we have got a solution with an empty Web API project. (By the way, I know that you guys are pretty familiar with, or even experts in these steps so far, but for new comers I don't want them to have to look around at other articles. This is one stop shop. Thank you for your patience :)
Setting Up Layers
Like all other typical application development, we are also using the "n" layered architecture. I mentioned "n" layer because, I myself am not sure how many layers am I going to create. All the layers I am going to create will be class library project. I'll explain how to create one layer, the remaining layers you can create by simply following the same process.
As you know, right-click the solution and add new project as shown below. The one I am creating is for Data Access and holding Data Base entities and hence I called it "WebApi.Kod.PotLuck.DbEntities".
Just as I've shown, you have to create the below mentioned layers. I've created around seven layers. You might be wondering why we need seven layers for this simple application. Whether the application is simple or complex, we always have to keep a door open for extensibility of the application. Always keep in mind that the application will grow one day or other. So you want to make sure you have a stable foundation for a better future :)
Take a look at the layers which I have created and we will explain one by one as we make use of it. After creating these projects, remove the default Class1.cs file from all the projects simply because "I don't like it."
Now we are done with the skeleton of our application. Are you ready to start coding? Not yet? Hmmm! OK then, we can do some more set ups.
Setting Up Entity Framework 6
Before we start coding any application, I'm sure every developer will wonder where I get data and where I store the data. For this application I am going to use SQL Local Db instead of using SQL server. This is so that it will be easy for developers using this article to download and configure the application easily without any issues, as well as being very easy to replace with SQL Server if you are using SQL Server DB as well.
Next question: How are we going to access data? We will be using Entity Framework 6.0 for Data access. Entity Framework is available as a nugget package. We just have to download it and install it for all the projects which we have just created. I mentioned for all the projects, as in some way or another we will be using some components of Entity Framework in almost all the projects.
So let's go ahead and download it and install it from NuGet.
On clicking the manage nugget package, an item will open up a window as shown below, then search for Entity Framework in the search box. Make sure that you have selected all the items marked in red box as it is.
Click the install button and it will prompt you to select the projects in which you want to install the framework. Since I wanted that to be installed only in the repository layer, I only checked the repository project.
On clicking OK and accepting license agreement, the Entity Framework nugget package will be installed into your project.
Also, the same way we have to add one more nugget for Local DB, but we just need local db in the main Web API project.
You might be wondering what installing a nugget package means, right? For those who are new to nugget, it's just downloading the package from the online nugget server and adding the required DLLs and making the required modifications in your project config files. It also adds some files and folders if is required for that package to work. Instead of us doing all those complicated, time consuming steps manually the nugget package manager will do all those tedious tasks for us. Isn't it great?
We are done with our basic requirement for coding.
Creating Code First Database Entities
We will be using a code first approach for this application. To create a code first model, first we have to decide what our Db table will look like and what columns we will need. Then we have to create corresponding Db classes for those identified tables with columns. All the Db models will be added in to the WebApi.Kod.PotLuck.DbEntities project. Now you might be thinking, "You are going to add Db models, so why is the project name DbEntities?" Right? I would say it's up to you to name the project as DbEntities or DbModels.
Initially, I'll be creating two Tables for our purposes and then we can keep on adding functionality as required on the fly. My two tables would be:
- PotLuckEvent
- Member
An event can have many members and a member can join as many events he/she wants. And the relationship between the tables will be a many to many (will discuss this shortly). So I'll be adding these classes in the DbEntities project with required properties(columns). One more thing we have to do is to identify the columns which we expect in both the tables. Then create an abstract class and place all the common properties in the abstract class.
Make this abstract class as base class for all the entities which we are going to create. I created one abstract class, BaseEntity
, with the following displayed properties(columns).
As seen above, the Id filed will be the primary key for the tables and remaining as usual, the property names itself is self-descriptive (can be called as Audit fields). I created the entities for the other two tables as well.
As shown in the images 11 and 12 I've inherited the BaseEntity
abstract class also. We are ready with the entities now. The next step is to create a Data Context.
Creating Data Context
What is Data Context? The msdn definition for data context is:
"The primary class that is responsible for interacting with data as objects is System.Data.Entity.DbContext (often referred to as context). The context class manages the entity objects during run time, which includes populating objects with data from a database, change tracking, and persisting data to the database."
https://msdn.microsoft.com/en-us/data/jj729737.aspx
This definition is pretty simple and straightforward to understand.
As the msdn link shows, let's create a context class for us as well in the DbEntities Project with our two entities.
Instead of creating Data Context with concreate implementation of Dbset, I created context with IDbset. I prefer to code against interface than concrete class. It is pretty simple to create a Data Context, I just added a class in our DbEntities project which inherits from System.Data.Entity.DbContext and added required Db sets in it. One more thing I did is, I added one more folder in the project to keep the Db context just for organizing purposes. And the context will look like the below (Img 13).
Setting Up Relationships and Configuring Properties
Relationships and mapping/configurations can be done in two ways in Entity Framework. The first is using Fluent API and other by data annotations.
Here I'll be using the Fluent API type since we can solve more problems using Fluent API than data annotations in complex scenarios (like if you are trying to do a code first with an existing Data base). For configuration purposes I'll be adding one configuration class for each model which we created.
It's pretty easy for setting up composite keys and all different flavors of keys using Fluent API, also creating and managing indexes are also not complex.
For configurations, I created a folder called DataBaseConfiguration inside the same DbEntities Project. I'll be adding two classes in it; one for each entity as I mentioned. I will be coding required configuration in those files; the configuration classes will be inheriting from the Entity Framework System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<T>
class. My configuration class will look like below image:
If you looking at the image 14, you can see that I made the primary key as a db generated identity column and the second line, HasKey will indicate that the Id field is the primary key. It is not necessary in Entity Framework to mention primary key explicitly. By default, Entity Framework will detect the column/property with the name Id/ID or table name followed by Id as primary key for the table.
Try doing the same type of configuration for the other entity. Hopefully you succeed in that.
The next step is to configure the relationship between the tables. I already mentioned that we will be going for a many to many relationship. For example, a Potluck Event can have as many members as we want and a member can join as many Potluck events as deired. :)
For holding the related entities, we have to have navigation properties in both the Entities. We have to declare the navigation properties as virtual properties.
In the member model, you can create the property of type ICollection
for the Potluck Event as below and vice versa in the Member model. The code look like below:
public virtual ICollection<PotLuckEvent> MyEvents { get; set; }
One important thing! Do not forget to instantiate the navigation properties from the model constructor. Now both the models will look this:
Take a look at the constructors from image 15; you can see that I've instantiated the navigation properties with hash set. (Why hash set?). We are pretty much done with the Models. Next is to set up the relationship. I'll be doing this in the Entity configuration files which we created before. Since we are planning to have many to many, it's fine to set up the relationship in one entity configuration file. Here I prefer to do the set up in the PotLuckEventConfig file for no reason.
So as we all know, for a many to many relation we need a junction table/join table to map the many to many. Let's see how we are going to do that.
Look at the HasMany Portion highlighted that is the portion which we wired up the relationship. Try reading it. Could you understand anything? Just plain and simple English, right? :).
Quote:
Read Like this: PotLuckEvent has many EventMembers with many MyEvents (Of type PotLuckEvent).
Simple right That's it.
Let's take look at the second portion Map. This is the portion which creates the junction table. What the code is actually trying to achieve is to map the relationship to a junction table with the name "EventMember" and with two columns: PotluckEventId and MemberId. It is not necessary that you have to name the column the same way I did. You can name with whatever naming convention you have in mind.
Here the left column will be mapped with the PK from PotLuckEvent since we are creating relation in PotLuckEvent's configuration file. To know more about the EF relationships you can read the following msdn link: https://msdn.microsoft.com/en-us/data/jj591620.aspx.
So we are done with models and relationships. Now let's try to create Db with same data.
One small but big thing we forgot: We created all the configurations and everything but we forgot to tell the DbContext that we created configuration files and you have to use those files going forward for the Models in the context. Hmmm. To achieve this, we have to override one method from the context and have to code the plumbing in that method.
Done!
Setup Data base with Test Data (Seeding)
We are done with Entities, Context and relationships. Before continuing further, we have to make sure that the Db is getting created as we expected. For this, let's go ahead and create Data base initializer.
Quote:
What is Data base initializer? We simply initilize the Data Base with data as per conditions while the application loads
Again, I created one more folder in the same DbEntities project called DbInitializer and added one class file in it called PotLuckDbInitializer
.
As you see below, this initializer can be inherited from two different types of System.Data.Entity.DbContext. It depends on when(conditions) we have to initialize the db.
Image 18 shows two classes. One will help us to create a db initializer which will drop and create the db each and every time we run the application. The other will drop and create the db only when a change in the model happens (like column name change, data type change etc.). More succinctly, whenever schema or type change happens. For now we can use the second one. Just update and create the db whenever a change in the model happens. One important thing is that we have to pass our data context as type parameter to the base class.
As a next step, we have to override a virtual method from the base class called Seed
in the child class. In that method, we have to write the code to populate the db with some sample data.
namespace WebApi.Kod.PotLuck.DbEntities.DbInitializer
{
public class PotLuckDbInitializer : DropCreateDatabaseIfModelChanges<PotLuckContext>
{
protected override void Seed(PotLuckContext context)
{
var members1 = new List<Member>
{
new Member{AddressLineOne="Test Address 1",City="Test City",ContactPhoneNumber="123-777-7656",CreatedBy=1,CreatedTime=DateTime.Now,Email="test@gmail.com",FirstName="Test",HouseNumber="1234",LastName="Test LastName",LastUpdatedBy=1,LastUpdatedTime=DateTime.Now,NickName="Test Nick",State="CT",Zip="17112"}
};
var members2 = new List<Member>
{
new Member{AddressLineOne="Test Address 2",City="Test City",ContactPhoneNumber="123-777-7656",CreatedBy=1,CreatedTime=DateTime.Now,Email="test@gmail.com",FirstName="Test",HouseNumber="1234",LastName="Test LastName",LastUpdatedBy=1,LastUpdatedTime=DateTime.Now,NickName="Test Nick",State="CT",Zip="17112"}
};
var plEvent = new List<PotLuckEvent>
{
new PotLuckEvent{CreatedBy=1,CreatedTime=DateTime.Now,EventAddressLineOne="Main Street",EventCity="Maryland Heights",EventDateTimeFrom=DateTime.Now,EventDateTimeTill=DateTime.Now,EventDescription="Test",EventName="Test Event 1",EventState="MO",EventZip="63043",LastUpdatedBy=1,LastUpdatedTime=DateTime.Now,EventMembers=members1},
new PotLuckEvent{CreatedBy=1,CreatedTime=DateTime.Now,EventAddressLineOne="Main Street",EventCity="Maryland Heights",EventDateTimeFrom=DateTime.Now,EventDateTimeTill=DateTime.Now,EventDescription="Test",EventName="Test Event 2",EventState="MO",EventZip="63043",LastUpdatedBy=1,LastUpdatedTime=DateTime.Now,EventMembers=members2},
};
plEvent.ForEach(x => context.PLEvent.Add(x));
context.SaveChanges();
}
}
}
The above is the source code I used to populate sample data as seed. I overrode the seed method from the drop create class also created two members and one event list. If you look closely in the PotLuckEvent list you can see that I've assigned the Member list to the EventMembers navigation property of the Event list. I did so in the expectation that, since I set up all the relationships and everything properly, the data which I provided should populate the member table. Anyway, let's see what's going to happen.
Also you can see at the very bottom of the code, I am iterating through the event list and saving data into the context.
Configuring Local DB
I mentioned in the beginning of this document, I'll be using Local Db as a Data base for this application. Let's see how are we going to configure our application to use Local DB. For that we have to download a NuGet package for Local Db Provider. You can find the provider form NuGet package as shown below.
Then install it.
By default it will add a default connection string in your Web config file. If you want to change the name of the connection string, just go ahead and change it from the Web config file and don't forget to change the connection string name from the DB Context.
The default connection string created by the NuGet package will be like image 20. Here I'll be using the connection string name as PotLuckConnection. And I changed in Db context class and in the Web.config File as well. Now my files are looking like image 21.
That's it
One question: If I want to use SQL Server or SQL Server Express instead Local DB, what changes do I have to make? Hope you got it!
Testing Db Creation and Relationship
To test whether the settings which we have done until now are working properly and creating Db with tables as expected, I am going to create a default Controller in the WebAPI.Kod.PotLuck project and will try to get all the records from the db. By doing so, my expectations are:
- Application should create a Local Db instance.
- Application should create three tables in the db as below.
- PotLuckEvent
- Member &
- EventMember
- PotLuckEventId(Column 1)
- MemberId(Column 2)
- Application should populate all the three tables with data which we provided in the seed.
- Should return records from the Db.
To achieve this, I will not following any layered approach of calling the db context, I am just calling the Potluck Context Directly from the controller as shown below.
Build and try running the application. I hope you were able to build the application without any errors. OK! Well and good. I'll be hitting the Web API with the help of Fiddler. (We have got other rest API testing tolls which comes with Google Chrome as a plugin called Postman.) Keep your application from Visual Studio in running mode then hit the API using Fiddler as shown below.
OK! Just take a look at the URL which I've used http://localhost:55523/api/Default and request the type as GET. It made me wait for a couple of seconds and returned me and exception as shown below.
The exception was something about the serialization of object, saying "Self refrencing loop dectected." This was because JSON was not able to serialize an object with circular reference
What is Circular Reference?
Yep. It's our many to many relationship causing this issue, like member has got event and events has members so it will confuse the serialization engine while trying to serialize. So we have to fix that by adding two lines of code in the WebApiConfig.cs file. I just added the following lines of code.
json = config.Formatters.JsonFormatter;
json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignor;
Now my code look like the image shown below, image 24.
Now try running the application. Yep. The issue is fixed and I am getting some response back as expected. That means the Data base is getting created properly and is populating data. And returning it well, as expected.
You can see that the Id and Created date time etc. defined in the abstract class also got created in here. But we have to check where the db is created and the names of the tables are as well, right? Sure! Let's see how the Tables look like. For that, we have to go to Visual Studio solution explorer and click the Show All Files Icon, then open up the App_Data Folder. You can see one .mdf file got created. Double click on it then it will open up a Server explorer window for you on the right side with the data base and tables in it. So you can see that all the tables in the server explorer as shown in the image below, image 26.
Hope you enjoyed learning with me until now! Now comes the fun part. :)
Creating Models/Business Entity
The communications to and from the repository should be a business entity, and can also be called model or business model. And all the business operations will be performed on the models from the business logic layer.
Why introduce models?
The main purpose is to avoid unintentional leaking of DataBase related entities to the business layer. The leaking of database related items to BLL will make it tightly coupled with the current db repository. Here my plan is to make it as independent as possible. So one piece of data will be transformed to three types of objects before it leaves the controller/Web API.
So looking at the above diagram, we already have Db Entities /Entities with us now the one we created at the beginning. Next we have to create Business Model. The Business Model/entity which you are going to use can be the same as the Db Entity, but still I prefer to have a separate section for Business Model. One of the reasons I already explained above are some of the other reasons are like: Sometimes the Db which you are going to use might not have been created in the naming convention which you require, or for specific business reasons you may have to use a different name for a field for db entity, or you may not want to expose all the fields from the db to the business model, etc. There can be many reasons. As a best practice and as a scalable design, it is always better to have different models for separating business layer with Repository.
Quote:
The More Complex your application, the more useful the intermediate types would be.
If you want to make modifications to the repository, or have to introduce a new repo and db entities with new namingsall you have to do is plug the output of the new repository to the Business model. Just change the mapping, that's it. You don't have to touch the business layer at all.
So we are done with the models.
From the above snap shot you can see that I've removed the audit fields like last updated and the created fields. I also renamed the Id fields with appending the model name in the front.
Repository
What is Repository?
I would say repository is one of several ways/patterns to perform data access for an application. Address the issues like separation of concern, testability, caching etc. It hides the data access logic from the other interfacing layers.
I know that most of us are familiar with the Data Access Layer, so what is the Difference between Data Access Layer and Repository Layer? I would say, "Since I am implementing Repository Pattern for accessing data in my DAL, I would call my DAL as Repository Layer." A more precise answer: Data Access Layer which implements Repository Pattern is called the Repository Layer. Ultimately both DAL and Repository are trying to achieve the same goal, i.e. "separation of concerns." One advantage I've noticed in Repository Pattern is that it makes unit testing more easy in the way that we can mock the repository easily using some mocking frameworks.
Also I've heard that Repository is part of Domain Driven Design (DDD). Since I am not familiar with that approach, I don't have any opinion connecting Repository and DDD. Sorry for that.
Please note: Whatever I've said above is strictly personal as per my understanding and experience.
You can read more about repository over here: https://msdn.microsoft.com/en-us/library/ff649690.aspx
Creating Generic Repository Interface First
To create a repository, first we have to identify all the operations we have to perform against an entity. Very basic db operations are as shown below all the remaining will be the combination of those operations.
- CREATE
- READ
- UPDATE &
- DELETE
Also known as CRUD operations. In our repositories we can follow the same pattern. Since we identified the operations, now we have to create repository interface(s). Why interfaces?
- Coding against interface is good than coding against Implementation/Concrete classes.
- Will make IOC and Mocking easier
Here for now, we will be creating two interfaces
- IPotLuckEventRepository
- IMemberRepository.
So I am done with our repository interface with some basic method signature in it. The methods which I created are as shown below:
- GetAsync
- InsertAsync
- UpdateAsync
- Delete
You might have noticed the Async at the end of all the methods. Why? Because we will be using Task, async and await to make our application perform better and be more responsive.
OK, look at the above image. I've highlighted the GetAsync
method, which is really powerful and reusable one since it uses expression as the input parameter and the return type is of IEnumerable
.
- What is Expression?
- What is the Benefit of Using IQueryable?
Let's Implement It
I created Interface as generic, but I am going to create repository as specific. Why? Good question. Because I just wanted to avoid another mapping layer. Also, I may be able to avoid selecting unnecessary fields from db by having a generic repository. Finally, to avoid Leakage of DB entities to BLL
Let go ahead and implement this in to our Member repository.
public class MemberRepository : IRepository<MemberMdl>
The portion which I highlighted is the mapping region which maps data from DbEntities to Business Model. So we will form the query with only the required fields and the DB Server will return only that much.
The image 32 can be refactored as 32-A. What I did is, I extracted the Select statement projection for the Method and created it as an Expression AsMemberMdl and I used that as a selector for the Member Dbset. By the way, we can avoid some clumsiness in the repository method and AsMemberMdl expression can be reused in the same class for other methods as well.
I implemented the same for the Event repository as well. Let's go ahead and implement the Manager in the business layer now.
Coding BLL
Whenever we start writing any new layer implementation, we need to find a place for dumping all the commonly and frequently used variables and functionalities.
Here also we have to write a generic base class that holds repository for a Manager layer. Why I said generic base class is, for an EventManager
class we want the repository property to hold the event repository and for MemberManager and I want the repository property to hold the Member repository.
I don't want a property which holds all the repositories and exposes the repository to unnecessary manager class. For example, I don't want to see the MemberRepository in EventManager and vice versa
In one word: "Abstraction." Exposing only necessary behaviors.
Let's see how such a base class should look like
It's a very simple base class just for holding repository and adding a layer of abstraction. Also, I wanted all the manager classes to follow a standard of using the variable Repository instead of using lots of other different naming conventions. In future, if you want to hold cache objects or properties, you can house that stuff into the base class.
Quote:
A question may arise in your mind: What if I want to use multiple repositories in my manager class? My answer will be: As long as you are using a db with a proper relationship set in place, you will seldom end up in a situation of using multiple repositories in a manager class. If that kind of situation arises, you just have to inject it as a constructor and assign it to another repository property in the manager. That's it .
Implementing Base Manager Class
I just created the manager class by implementing the BaseManager we just created. Also I extracted an interface called IMemberManager
out of it so that we can use the IMemberManager
interface to code in the controller.
I always prefer to create the concrete implementation first, then I'll extract an interface out of it, because the Visual Studio makes it that easy. We don't have to hand code the interface again. Click on the class name then Ctrl+R+I IDE will create an interface for you (just personal preference).
In image 34 you can see that I've implemented the method GetEvents
as well, which internally make use of the Repository property from the base class.
Likewise, I hope you can create a manager class for the event as well. The next step is to call the manager method inside the Controller.
Controller The Orchestrator
Unlike MVC controllers, The Web API controllers inherits from ApiController Base type. Whenever you create a Web API project, create it as a standalone one without having the MVC components in it, like shown in Image 3.
Let me go and create an API controller and action method for Member. While creating a controller, always try to keep it as lean as possible. Try not to include any kind of business logic in it because it's a bit difficult to test controller. I was able to create a controller and it looks like this:
You can see that the Members controller constructor accepts a dependency of the Manager and then the repository is being injected to the Manager from the manager class.
Rule of thumb: You must not add the reference of repository in the Web API project. Do not leak any of the repository related objects to Web API layer. Everything should end at BLL. So the Controller can be re-written as:
As far as our current business logic layer concerned, we don't have anything much over here. If we have got something, all the operations like scrubbing and massaging of data should happen in the BLL, not in controller.
The role of the controller is just to hand over the request and transform the Model to DTO coming back from manager as response and send across the wire.
Trial Run
Let's run this application and see whether it's working as expected or not. So I am done with creating the Events and Member Controllers. Let's run the application. Here I am trying to run the Events controller using POSTMan. Post man is a Google Chrome extension. You can download it from Google Chrome extensions. It is a very simple to use tool.
As I said, I got wonder full exception. Highlighted in the above image. The error says as below:
"ExceptionMessage": "An error occurred when trying to create a controller of type 'EventsController'. Make sure that the controller has a parameterless public constructor."
Eurekaaa! I got it! But we didn't resolved the dependency of the repository, so now let's go ahead and resolve the dependencies for all the controllers. We decoupled everything, but forgot to resolve the dependancies. Hmm ... sad.
Dependency resolution using StructureMap
Structure map is one of the high performing and simple to use IoC Container. Structure map for Web API is available as a NuGet package. NuGet Package made configuring Structure Map simple and easy. Got to Tools-->NuGet -->Package Manager-->Package Manager Console
PM> Install-Package StructureMap.WebApi2.
This will install the structure map in our web API Project. We just need the structure map Web API 2 to be installed in the Web API project. Make sure you selected the Default project as The Web API project. This is just another way of installing NuGet Packages beyond what I mentioned earlier. After installation of the package, if you take a look at the solution, you can see some files and folders got added as extra as below.
Those are all the supporting files for Structure map. Out of those files our area of interest is in IoC.cs. The File IoC is the converging point of the dependency resolution classes from the below layers You will understand this statement in a short while. As for the next step we have to install a different flavor of structure map in to the Business Logic Layer and in the repository. In the below image you can see the details of the NuGet Package.
And now add a folder called DependencyResolution in both the project and with a class file in it . You can name the class file as BusinessRegistry and RepositoryRegistery in the Business project and in the Repository project DependencyResolution folder respectively.
So we have to write a few lines of code in those files. Let's first take the repository registry. In that file we have to tell the structure map that Whenever a manager class asks for a repository of a specific type (Interface), provide the Manager with this particular repository which implements the requested interface type. And the syntax looks like this:
From the above image you can see the folder and file which I created. One important point to note is that the new class should inherit from the Registry Class which is part of the strecturemap NuGet Package you just installed. Also, make sure that you are using the two name spaces Highlighted.
using StructureMap.Configuration.DSL;
OK. We are done with this Repository registry, now let's modify the file inside the business registry in the same way. But you don't have to add the For<>, Instead you have to add Scan.
The scan of the structure map is intelligent enough to find out the class which implements the interface dependency which the caller is expecting.
Then why did we add For<>()Use
in the Repository Registry explicitly? Because the structure map is not intelligent enough to catch the dependency which we have like IRepository<EventMdl>
.
StructureMap Scan goes by Naming Convention
In the BLL, the scan showed in image 38-C will solve our dependency identifying problem and we don't have to explicitly mention the For<>()Use
. But we have to add one extra line of code other than the above mentioned in BusinessRegistry. That is for including the RepositoryRegistery with in BusinessRegistry.
You have to use some aditional name spaces for the Scan to happen from strecture map as listed below .
using StructureMap.Configuration.DSL;
using StructureMap.Graph;
One Last Step
Now we have to tell the Web API Structure map that we have got another Dependency resolution registries as well scattered in other layers.
In this case, we don't explicitly mention the Web API Dependency resolver about the repository registry, but we just have to mention about the business registry Because we already told the business registry about the Repository Registry with the help of the include statement from image 38-C. He will take care of that hence avoiding referring the Repository Project in the Web API layer even to mention the dependency resolver registry.
The place which we have make this code tell the WebAPI Dependency resolver is in the file called IoC.cs, whic isinside the WebApi project DependencyResolution Folder as below (38-D).
OK we are done.
Let's try running this once more
Awesome. It's working fine for me. What about you?
Data transfer object (DTO)
Our Web API is working fine now, but still I think we are missing something. Yep. Look at the place where we create the Response object. We are sending Model over the wire. Hmmm. We are not supposed to transfer a Business model over the wire, just DTO .
Quote:
Then what is a DTO? As per Wikipedia: A DTO is Data transfer object (DTO) is an object that carries data between processes.
Then what is the specialty of it?
Again as per Wikipedia: The difference between data transfer objects and business objects or data access objects is that a DTO does not have any behavior except for storage and retrieval of its own data (accessors and mutators). DTOs are simple objects that should not contain any business logic that would require testing.
Let's go and write some DTOs then. In our case, we can use the same Business model, but as per our theory, DTO should not contain any business logic that would require testing.
I created two classes called EventDTO and MemberDTO in the DTO Project. Then I copied the same properties from the Model to respective files, but I did not copy the Collection Properties. As a next step, we have to write some extension methods to transform the Business Models to DTO.
We will be housing those extension methods in the Extension Project.
You might be thinking, "Why did I create a separate project for writing extension methods?" The reason behind that is, I just wanted to see the extension method for the models in the controller. Also, it should not be tied up with the Business model as well. Because the DTO may vary API by API. It depends on what you want to transfer over the wire and what your client wants to see.
If you are tying up the extensions with the Business model, it will impact the reusability of the business layer. Like you are giving unnecessary methods to the other application which wanted to use the same BLL. On the other hand, if the other application wants to use the same DTOs then they can simply refer the FTO project and use the DTO and the Extension project along with the Business Logic Layer. We are just packing it separately, so that it can be used separately.
Hope you got the context now.
AutoMapper
While transforming data from one form to another, we have to write lots of code. To avoid that tedious hand written code, we have to take help from NuGet again. NuGet has got one package called AutoMapper. We have to download it and install it as usual.
Install-Package AutoMapper
Install this package only into the extensions project (you can have this in the repository as well). OK. I was able to install this successfully. Let's see how stuff works now.
Get on to the Models.Extensions Project and create class files for EventExtensions
and MemberExtensions
. Let's pick up the Event Extensions first...
I just wrote two extension methods, one for EventMdl
and other for the IEnumerable<EventMdl>
. Look at those methods how simple the mapping syntax is. For further reading about AutoMapper, please follow the link: https://github.com/AutoMapper/AutoMapper/wiki/Getting-started. One thing I would like to call out is that the trade for less number of code may be a performance hit. I am not sure about it.
What is Yield return?
Let's use this in our controller.
Quote:
Keep in mind that Transform the Business model into DTO just before you send it over the wire.
So best place to transform is from the controller.
Let's run the application and see whether it works or not. Don't wait for me, just do it.
It worked for me. I got a response back as DTO. What about you? OK I hope you also got the same result. Great!
I felt a little bit odd, though. Looking at the controller action which returns IHttpActionResult
I was not able to make out what type of data it's sending over the wire. I think we have to fix that readability issue. <sh4>How then?
Changing the return type of the action method is one way. One other standard way of doing it is decorating the action method with an attribute called ResponseType
in the System.Web.Http.Description
namespace. I prefer the second approach.
I decorated the action method and now it looks like this:
OK, now I can easily say what the return type of this action in a single look is interesting, right? I applied the same for the Member as well. Both the controllers are working fine for me and spitting out DTO.
Quote:
DTOs and Business Models are the best remeady for seralization circular refrence issues!
Now you can try removing the code which I mentoned in img 24 and try running the application. The application will run fine.
Help! Help! Call 911
Now we are done with the Web API successfully, just think about consuming applications now. How they will they able be to consume without proper documentation? They need some information about the API, right? Some kind of documentation or WIKI kind of stuff? Hmmm. Again, preparing documentation about an API is a tedious task.
Here NuGet will help us again. There is a NuGet plugin package called Web API help. And the magic word is?
PM> Install-Package Microsoft.AspNet.WebApi.HelpPage.
Let's go ahead and install this package and see how this guy provides us with the help documentation (make sure that you install only in the Web API project).
After installation, I could see a bunch of files got created under the Area Folder in the Web API project.
What is Area in MVC?
Don't be scared, you don't have to do anything with that, other than simple tweaks.
- The first thing we have to do is go ahead and register the area created by the NuGet package in the Global.asax file.
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
}
}
- Add an XML Document called XMLDocument.xml (name whatever you like) in the App_Data Folder
- Configure the XML doc in Web Application Properties as below.
- Uncomment the below shown line of code.
config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
Run the application now.
With the URL http://localhost:55523/help. I got a wonderful exception as shown below. If you are lucky enough you will not get this exception.
Looks like it's something related to Dependency Injection. After a long search in Google, I wasn't able to find the solution for this issue. You just have to add one line of code in the StructureMap Default registry file as shown below:
Now run the application. Hurray! My help page started showing up. Great, but now I am not landing on the help page by default, it;s taking me to some crashed like page.
I have to type http://localhost:55523/help. to see the help page now from here. I don't like this. I want to land on the help page while running the application as a default. For this we have to do a little tweak.
WebApi.Kod.PotLuck\Areas\HelpPage\HelpPageAreaRegistration.cs--> open it
context.MapRoute(
"Help Area",
"",
new { controller = "Help", action = "Index" }
);
You have to add the boxed code in HelpPageAreaRegistration.cs. Now just run the application. You will land on the help page directly. Your help page will look like this:
The description which you are seeing on the right side is from the summary which you provided on top of the Action
method.
Now we can directly give our API's URL to anybody, without any added documentation.
We have a complete API now, but if we want to test the API we have go through POST Man or Fiddler or other API testing tools. Thankfully we have one more plugin from NuGet for Testing the Web API. Yep
Simple Test
Again, it's a NuGet package. Just install it from NuGet and use it. And the Magic Word is?
PM> Install-Package WebApiTestClient
Just install this package for Web API project.
While installing the package using Package manager console, I got an exception. While installing make sure that you are running Visual Studio in Administrator mode other wise you will get exceptions. Just install this package for Web API project.
I installed it and after installation one text file opened up asking me to add a two line of code in <sem>Areas\HelpPage\Views\Help\Api.cshtml.
@Html.DisplayForModel("TestClientDialogs")
@Html.DisplayForModel("TestClientReferences")
I just copied the above two lines and pasted in the Api.cshtml file as shown below and ran the application. It took me to the API Landing Page again, but I didn't find any thing new in here.
Upon clicking the link it will open up a browser window. At the right bottom of the browser window you can see a Button labled Test API .
Click the Button. A pop up will open up. That's your testing destination for the particular End point (Action Method).
Great!
All the methods which we created until now have been without any input parameter. Just to show you how the test window will react for end points with Inputs, I'll write a simple end point which accepts an int
.
I executed the API and as usual and it took me to the landing help page. From there I clicked on the end point which I have to test (in this context) the one which accepts int
as input. And the test pops up and result will look like this:
Upon clicking Send, we will get the response back in another pop up window.
References
Conclusion
WEB API is simply awesome. Thank you! I tried to cover as much as possible for a beginner to start writing an extensible Web API.
Thank you very much for reading this article. If you find anything wrong or that can be improved, please leave it in the article forum below.
Also, I'm planning to put up something on Exception Handling and Security of Web API as next article. I will try to include the POST operations as well in the coming sections.
Thank you once again for reading this.