ASP.NET Boilerplate can automatically generate web api layer for your application layer. Say that we have an application service as shown below:
public interface ITaskAppService : IApplicationService
{
GetTasksOutput GetTasks(GetTasksInput input);
void UpdateTask(UpdateTaskInput input);
void CreateTask(CreateTaskInput input);
}
And we want to expose this service as a Web API Controller for clients. ASP.NET Boilerplate can automatically and dynamically create a Web API Controller for this application service with a single line of configuration:
DynamicApiControllerBuilder.For<ITaskAppService>("tasksystem/task").Build();
Thats all! An api controller is created in the address '/api/services/tasksystem/task' and all methods are now usable by clients. This configuration should be made in the module initialization.
ITaskAppService is the application service that we want to wrap with an api controller. It is not restricted to application services but this is the traditional and recommended way. "tasksystem/task" is name of the api controller with an arbitrary namespace. You should define at least one-level namespace but you can define more deep namespaces like "myCompany/myApplication/myNamespace1/myNamespace2/myServiceName". '/api/services/' is a prefix for all dynamic web api controllers. So, address of the api controller will be like '/api/services/tasksystem/task' and GetTasks method's address will be '/api/services/tasksystem/task/getTasks'. Method names are converted to camelCase since it's conventional in javascript world.
We may have many application services in an application and building api controllers one by one may be a tedious and forgettable work. DynamicApiControllerBuilper provides a method to build web api controllers for all application services in one call. Example:
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.Build();
ForAll method is generic and accepts an interface. First parameter is an assembly that has classes derived from given interface. The last one is namespace prefix of services. Say that we have ITaskAppService and IPersonAppService in given assembly. For this configuration, services will be '/api/services/tasksystem/task' and '/api/services/tasksystem/person'. To canculate service name: Service and AppService postfixes and I prefix is removed (for interfaces). Also, service name is converted to camel case. If you don't like this convention, there is a 'WithServiceName' method that you can determine names. Also, There is a Where method to filter services. This can be useful if you will build for all application services except a few one.
We can override configuration after ForAll method. Example:
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.Build();
DynamicApiControllerBuilder
.For<ITaskAppService>("tasksystem/task")
.ForMethod("CreateTask").DontCreateAction()
.Build();
In this code, we created dynamic web api controllers for all application services in an assembly. Then overrided configuration for a single application service (ITaskAppService) to ignore CreateTask method.
By default, all methods are created as POST. So, a client should send post requests in order to use created web api actions. We can change this behaviour in different ways.
We can use WithVerb for a method like that:
DynamicApiControllerBuilder
.For<ITaskAppService>("tasksystem/task")
.ForMethod("GetTasks").WithVerb(HttpVerb.Get)
.Build();
We can add HttpGet, HttpPost... attributes to methods in the service interface:
public interface ITaskAppService : IApplicationService
{
[HttpGet]
GetTasksOutput GetTasks(GetTasksInput input);
[HttpPut]
void UpdateTask(UpdateTaskInput input);
[HttpPost]
void CreateTask(CreateTaskInput input);
}
In order to use these attributes, we should add reference to Microsoft.AspNet.WebApi.Core nuget package from your project.
Instead of declaring HTTP very for every method, you can use WithConventionalVerbs method as shown below:
DynamicApiControllerBuilder
.ForAll<IApplicationService>(Assembly.GetAssembly(typeof(SimpleTaskSystemApplicationModule)), "tasksystem")
.WithConventionalVerbs()
.Build();
In this case, HTTP verbs are determined by method name prefixes:
We can override it for a specific method using WithVerb method or HTTP attributes.
You can use the dynamically created web api controller via ajax in javascript. ASP.NET Boilerplate also simplifies this by creating dynamic javascript proxies for dynamic web api controllers. So, you can call a dynamic web api controller's action from javascript as like a function call:
abp.services.tasksystem.task.getTasks({
state: 1
}).done(function (result) {
//use result.tasks here...
});
Javascript proxies are created dynamically. You should include the dynamic script to your page before use it:
<script src="/api/AbpServiceProxies/GetAll" type="text/javascript"></script>
Service methods return promise (See jQuery.Deferred). You can register to done, fail, then... callbacks. Service methods use abp.ajax inside. They handle errors and show error messages if needed.
You may want to pass custom ajax parameters to the proxy method. You can pass them as second argument as sown below:
abp.services.tasksystem.task.createTask({
assignedPersonId: 3,
description: 'a new task description...'
},{ //override jQuery's ajax parameters
async: false,
timeout: 30000
}).done(function () {
abp.notify.success('successfully created a task!');
});
All parameters of jQuery.ajax are valid here.
'/api/AbpServiceProxies/GetAll' generates all service proxies in one file. You can also generate a sinle service proxy using '/api/AbpServiceProxies/Get?name=serviceName' and include the script to the page as shown below:
<script src="/api/AbpServiceProxies/Get?name=tasksystem/task" type="text/javascript"></script>
ASP.NET Boilerplate can expose dynamic api controllers as angularjs services. Consider the sample below:
(function() {
angular.module('app').controller('TaskListController', [
'$scope', 'abp.services.tasksystem.task',
function($scope, taskService) {
var vm = this;
vm.tasks = [];
taskService.getTasks({
state: 0
}).success(function(result) {
vm.tasks = result.tasks;
});
}
]);
})();
We can inject a service using it's name (with namespace). Then we can call it's functions as regular javascript functions. Notice that we registered to success handler (instead of done) since it's like that in angular's $http service. ASP.NET Boilerplate uses $http service of AngularJs. If you want to pass $http configuration, you can pass a configuration object as the last parameter of the service method.
To be able to use auto-generated services, you should include needed scripts to your page:
<script src="~/Abp/Framework/scripts/libs/angularjs/abp.ng.js"></script>
<script src="~/api/AbpServiceProxies/GetAll?type=angular"></script>
ASP.NET Boilerplate makes it possible to inject service proxies in modules in a Durandal application. See the sample viewmodel:
define(['service!tasksystem/task'],
function (taskService) {
//taskService can be used here
});
ASP.NET Boilerplate configures Durandal (Require.js actually) to understand the 'service!' prefix and inject appropriate javascript service proxy.
ASP.NET Boilerplate creates Api Controllers on runtime. So, ASP.NET Web API's model and parameter binding is used to bind model and parameters. You can read it's documentation for more information.
FromUri and FromBody attributes can be used in service interface to advanced control on binding.
We strongly advice to use DTOs as method parameters for application services and web api controllers. But you can also use primitive types (like string, int, bool... or nullable types like int?, bool?...) as service arguments. More than one parameters can be used but only one complex-type parameter is allowed in these parameters.