Objective
Long time no update, before there are many things, so dragged for a long time, very sorry. Well, don't say much nonsense, let's start with the subject. This article still uses the previous season's project background (series address http://www.cnblogs.com/fzrain/p/3490137.html) to demonstrate the OData service, so we can directly use the previously built data access layer. But not to be sure to see everything before, we just borrowed the database access layer and built a shift to the database model (using the entity Framework Code first to build the database model).
With the foundation of data access, we can start building OData services.
First step: Create an empty Web API project
Open the solution for the project, create a new Web project, select the Empty Web API project (as shown), and remember to select the. Net Framework 4.5. After you've built your project, you need to add a reference to "EntityFramework" and "Learning.data" (Our data access layer).
Step Two: Add an OData reference
By default, the Web API is not supported for OData, so we need to add a reference to "Microsoft.ASP.NET Web API 2.1 OData"--open NuGet as shown:
Step Three: Configure OData routing
Open the "Webapiconfig" class that the system created for us in the "App_start" folder, where there is a register method and register the routing rules. The OData we need to configure is also written here, the code is as follows:
Public Static classWebapiconfig { Public Static voidRegister (httpconfiguration config) {//Web API Configuration and Services//Web API RoutingCONFIG. Maphttpattributeroutes (); Config. Routes.maphttproute (Name:"Defaultapi", Routetemplate:"Api/{controller}/{id}", defaults:New{id =routeparameter.optional}); Config. Routes.mapodataroute ("Elearningodata","OData", Generateedmmodel ()); } Private StaticIedmmodel Generateedmmodel () {varBuilder =NewOdataconventionmodelbuilder (); Builder. EntitySet<Course> ("Courses"); Builder. EntitySet<Enrollment> ("enrollments"); Builder. EntitySet<Subject> ("Subjects"); Builder. EntitySet<Tutor> ("Tutors"); returnBuilder. Getedmmodel (); } }
Although we are only using the OData service, I have not removed the default configuration because these two routing rules can coexist.
The above has configured the routing rules and Entity Data Model (EDM) for our OData service
The EDM primarily defines data types, navigation properties, and methods to accommodate OData formats. There are 2 ways to define an EDM, the first is a convention-based approach, we will use the "odataconventionmodelbuilder" class, and the other is "odatamodelbuilder".
Here we will use "odataconventionmodelbuilder " because it generates a link to the associated collection based on our defined navigation properties. Compared to writing less code. If you want to have more control over the associated set, then you can use "odatamodelbuilder".
We have added 4 different entities to the Builder object, note that the entity collection name defined by the string parameter "Courses" must match the name of the controller, that is, the name of our controller must be "Courses Controller ".
"Mapodataroute" is an extension method that can be used when we add a reference to an OData. It primarily defines the routing rules for the OData service: The first parameter specifies a name, which is not used by the client, and the second parameter is the URI prefix corresponding to the OData endpoint (the URI that accesses the courses resource in our case should be:/HTTP hostname/odata/courses). You can have multiple OData endpoints in the same application, just call the "Mapodataroute" method to specify a different prefix.
Fourth step: Add the first read-only OData controller
Now we create a Web API controller to handle HTTP requests like "/odata/courses" for OData URIs. Right-click the Controller folder, new, select the "Empty API Controller" template and name "CoursesController".
Once created, we first change our base class to "System.Web.Http.OData.EntitySetController". This generic base class requires 2 parameters: the first refers to the entity type that corresponds to the controller, and the second parameter refers to the type of the entity's primary key, the following code:
Public classCoursescontroller:entitysetcontroller<course,int>{Learningcontext CTX=NewLearningcontext (); [Queryable (PageSize=Ten)] Public OverrideIqueryable<course>Get () {returnCTX. Courses.asqueryable (); } protected OverrideCourse Getentitybykey (intkey) { returnCTX. Courses.find (key); } }
The "Entitysetcontroller" class defines a number of abstract and overridable methods to update and query entities, so you'll find that you can rewrite a lot of ways such as: Get (), Getentitybykey (), Createentrty (), Patchentity (), updateentity (), etc ...
As I mentioned earlier, we will create a read-only controller, which means that we only implement the read operation, explaining the implementation of the above code:
1. Rewrite the Get () method and attach the [queryable] attribute, which means we allow the client to send HTTP get to our endpoint and support Filter,order by,pagination operation in the URI parameter value. The queryable feature is an action filter that mainly converts and verifies the URI of the query and the corresponding parameters, which will have an unintended effect when the client query will take a lot of time or a lot of data (for example: Setting the PageSize property, This will only return 10 data to the client at once)
2. Overriding the Getentitybykey (int key) method will enable the client to send HTTP access to a single resource in the form similar to "/odata/courses (5)". Note: The key here represents the primary key for the corresponding entity.
Fifth step: Test the courses Controller
Now we're going to test our controller, and for all the requests we've designated the Accept header as "Application/json", so we'll get the lightweight JSON data, you can also specify the Accept The header is "Application/json;odata=verbose" or "application/atom+xml" to see the results.
Let's demonstrate the scenario:
1. $filter: We inquire about courses that are sometimes longer than 4 hours: send GET request http://{hostname}/odata/courses? $filter =duration GT 4
2. $orderby, $take: We need to sort by the course name and get the first 5 records: send GET request http://{hostname}/odata/courses? $orderby =name& $top =5
3. $select: We only need to get the value of the Name and Duration fields: Send GET request http://{hostname}/odata/courses? $select =name,duration
4. $expand: We need to obtain the corresponding subject and instructor for each course and arrange it in reverse order according to the course name: send GET request http://{hostname}/odata/courses? $expand =coursetutor, coursesubject& $orderby =name desc
With just 4 examples we can see that the username and password fields are included in our return results, but the information is not necessary for the client. ,
Fortunately, we just have to configure the EDM to not include the two fields in the returned results, specifically by adding the following code to the Generateedmmodel () method in the Webapiconfig class:
Private StaticIedmmodel Generateedmmodel () {varBuilder =NewOdataconventionmodelbuilder (); Builder. EntitySet<Course> ("Courses"); Builder. EntitySet<Enrollment> ("enrollments"); Builder. EntitySet<Subject> ("Subjects"); Builder. EntitySet<Tutor> ("Tutors"); varTutorsentityset = Builder. Entityset<tutor> ("Tutors"); TutorsEntitySet.EntityType.Ignore (S=s.username); TutorsEntitySet.EntityType.Ignore (S=S.password); returnBuilder. Getedmmodel (); }
Source Address: Https://github.com/fzrain/WebApi.eLearning