Browse Source

Handle basic URL conventions.

pull/96/head
Halil İbrahim Kalkan 9 years ago
parent
commit
0906e4f391
  1. 26
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs
  2. 2
      src/Volo.Abp/Volo/Abp/Application/Services/AsyncCrudAppService.cs
  3. 2
      src/Volo.Abp/Volo/Abp/Application/Services/IAsyncCrudAppService.cs
  4. 48
      src/Volo.Abp/Volo/Abp/Http/HttpMethodConventionHelper.cs
  5. 44
      src/Volo.Abp/Volo/Abp/Http/HttpVerbHelper.cs
  6. 26
      test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs
  7. 2
      test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/Application/PersonAppService_Tests.cs

26
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs

@ -226,8 +226,8 @@ namespace Volo.Abp.AspNetCore.Mvc
protected virtual string SelectHttpMethod(ActionModel action, AbpControllerAssemblySetting configuration)
{
return configuration?.UseConventionalHttpVerbs == true
? HttpVerbHelper.GetConventionalVerbForMethodName(action.ActionName)
: HttpVerbHelper.DefaultHttpVerb;
? HttpMethodConventionHelper.GetConventionalVerbForMethodName(action.ActionName)
: HttpMethodConventionHelper.DefaultHttpVerb;
}
protected virtual void NormalizeSelectorRoutes(string moduleName, string controllerName, ActionModel action)
@ -256,11 +256,29 @@ namespace Volo.Abp.AspNetCore.Mvc
protected virtual AttributeRouteModel CreateAbpServiceAttributeRouteModel(string moduleName, string controllerName, ActionModel action, string httpMethod)
{
var url = $"api/{moduleName}/{controllerName}/{action.ActionName}";
var url = CalculateUrl(moduleName, controllerName, action, httpMethod);
return new AttributeRouteModel(new RouteAttribute(url));
}
private static string CalculateUrl(string moduleName, string controllerName, ActionModel action, string httpMethod)
{
var url = $"api/{moduleName}/{controllerName}";
return new AttributeRouteModel(new RouteAttribute(url));
//Add {id} path if needed
if (action.Parameters.Any(p => p.ParameterName == "id"))
{
url += "/{id}";
}
//Add action name if needed
var actionName = HttpMethodConventionHelper.RemoveHttpMethodPrefix(action.ActionName, httpMethod);
if (!actionName.IsNullOrEmpty())
{
url += $"/{actionName}";
}
return url;
}
protected virtual void RemoveEmptySelectors(IList<SelectorModel> selectors)

2
src/Volo.Abp/Volo/Abp/Application/Services/AsyncCrudAppService.cs

@ -80,7 +80,7 @@ namespace Volo.Abp.Application.Services
return MapToEntityDto(entity);
}
public virtual async Task<PagedResultDto<TEntityDto>> GetAll(TGetAllInput input)
public virtual async Task<PagedResultDto<TEntityDto>> GetList(TGetAllInput input)
{
CheckGetAllPermission();

2
src/Volo.Abp/Volo/Abp/Application/Services/IAsyncCrudAppService.cs

@ -39,7 +39,7 @@ namespace Volo.Abp.Application.Services
{
Task<TEntityDto> Get(TPrimaryKey id);
Task<PagedResultDto<TEntityDto>> GetAll(TGetAllInput input);
Task<PagedResultDto<TEntityDto>> GetList(TGetAllInput input);
Task<TEntityDto> Create(TCreateInput input);

48
src/Volo.Abp/Volo/Abp/Http/HttpMethodConventionHelper.cs

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
namespace Volo.Abp.Http
{
public static class HttpMethodConventionHelper
{
public const string DefaultHttpVerb = "POST";
public static Dictionary<string, string[]> ConventionalPrefixes { get; set; } = new Dictionary<string, string[]>
{
{"GET", new[] {"GetList", "GetAll", "Get"}},
{"PUT", new[] {"Put", "Update"}},
{"DELETE", new[] {"Delete", "Remove"}},
{"POST", new[] {"Create", "Add", "Insert", "Post"}},
{"PATCH", new[] {"Patch"}}
};
public static string GetConventionalVerbForMethodName(string methodName)
{
foreach (var conventionalPrefix in ConventionalPrefixes)
{
if (conventionalPrefix.Value.Any(prefix => methodName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
{
return conventionalPrefix.Key;
}
}
return DefaultHttpVerb;
}
public static string RemoveHttpMethodPrefix([NotNull] string methodName, [NotNull] string httpMethod)
{
Check.NotNull(methodName, nameof(methodName));
Check.NotNull(httpMethod, nameof(httpMethod));
var prefixes = ConventionalPrefixes.GetOrDefault(httpMethod);
if (prefixes.IsNullOrEmpty())
{
return methodName;
}
return methodName.RemovePreFix(prefixes);
}
}
}

44
src/Volo.Abp/Volo/Abp/Http/HttpVerbHelper.cs

@ -1,44 +0,0 @@
using System;
namespace Volo.Abp.Http
{
public class HttpVerbHelper //TODO: Internal?
{
public const string DefaultHttpVerb = "POST";
public static string GetConventionalVerbForMethodName(string methodName)
{
if (methodName.StartsWith("Get", StringComparison.OrdinalIgnoreCase))
{
return "GET";
}
if (methodName.StartsWith("Put", StringComparison.OrdinalIgnoreCase) ||
methodName.StartsWith("Update", StringComparison.OrdinalIgnoreCase))
{
return "PUT";
}
if (methodName.StartsWith("Delete", StringComparison.OrdinalIgnoreCase) ||
methodName.StartsWith("Remove", StringComparison.OrdinalIgnoreCase))
{
return "DELETE";
}
if (methodName.StartsWith("Patch", StringComparison.OrdinalIgnoreCase))
{
return "PATCH";
}
if (methodName.StartsWith("Post", StringComparison.OrdinalIgnoreCase) ||
methodName.StartsWith("Create", StringComparison.OrdinalIgnoreCase) ||
methodName.StartsWith("Insert", StringComparison.OrdinalIgnoreCase))
{
return "POST";
}
//Default
return DefaultHttpVerb;
}
}
}

26
test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs

@ -34,8 +34,8 @@ namespace Volo.Abp.AspNetCore.Mvc
[Fact]
public async Task GetAll_Test()
{
//Ideally should be [GET] /api/app/person
var result = await GetResponseAsObjectAsync<ListResultDto<PersonDto>>("/api/app/person/GetAll");
//Ideally should be [GET] /api/app/person OK!
var result = await GetResponseAsObjectAsync<ListResultDto<PersonDto>>("/api/app/person");
result.Items.Count.ShouldBeGreaterThan(0);
}
@ -44,8 +44,8 @@ namespace Volo.Abp.AspNetCore.Mvc
{
var firstPerson = _personRepository.GetList().First();
//Ideally should be [GET] /api/app/person/{id}
var result = await GetResponseAsObjectAsync<PersonDto>("/api/app/person/Get?id=" + firstPerson.Id);
//Ideally should be [GET] /api/app/person/{id} OK!
var result = await GetResponseAsObjectAsync<PersonDto>($"/api/app/person/{firstPerson.Id}");
result.Name.ShouldBe(firstPerson.Name);
}
@ -54,8 +54,8 @@ namespace Volo.Abp.AspNetCore.Mvc
{
var firstPerson = _personRepository.GetList().First();
//Ideally should be [DELETE] /api/app/person/{id}
await Client.DeleteAsync("/api/app/person/Delete?id=" + firstPerson.Id);
//Ideally should be [DELETE] /api/app/person/{id} OK!
await Client.DeleteAsync($"/api/app/person/{firstPerson.Id}");
(await _personRepository.FindAsync(firstPerson.Id)).ShouldBeNull();
}
@ -67,9 +67,9 @@ namespace Volo.Abp.AspNetCore.Mvc
var postData = _jsonSerializer.Serialize(new PersonDto {Name = "John", Age = 33});
//Ideally should be [POST] /api/app/person
//Ideally should be [POST] /api/app/person OK!
var response = await Client.PostAsync(
"/api/app/person/Create",
"/api/app/person",
new StringContent(postData, Encoding.UTF8, "application/json")
);
@ -100,9 +100,9 @@ namespace Volo.Abp.AspNetCore.Mvc
//Act
//Ideally should be [PUT] /api/app/person/{id}
//Ideally should be [PUT] /api/app/person/{id} OK!
var response = await Client.PutAsync(
"/api/app/person/Update?id=" + updateDto.Id,
$"/api/app/person/{updateDto.Id}",
new StringContent(putData, Encoding.UTF8, "application/json")
);
@ -136,7 +136,7 @@ namespace Volo.Abp.AspNetCore.Mvc
//Ideally should be [POST] /api/people/{id}/phones
var response = await Client.PostAsync(
"/api/app/person/AddPhone?id=" + personToAddNewPhone.Id,
$"/api/app/person/{personToAddNewPhone.Id}/Phone",
new StringContent(postData, Encoding.UTF8, "application/json")
);
@ -160,7 +160,7 @@ namespace Volo.Abp.AspNetCore.Mvc
var douglas = _personRepository.GetList().First(p => p.Name == "Douglas");
//Ideally should be [GET] /api/person/{id}/phones?type=office
var result = await GetResponseAsObjectAsync<ListResultDto<PhoneDto>>("/api/app/person/GetPhones?id=" + douglas.Id);
var result = await GetResponseAsObjectAsync<ListResultDto<PhoneDto>>($"/api/app/person/{douglas.Id}/Phones");
result.Items.Count.ShouldBe(douglas.Phones.Count);
}
@ -171,7 +171,7 @@ namespace Volo.Abp.AspNetCore.Mvc
var firstPhone = douglas.Phones.First();
//Ideally should be [DELETE] /api/app/person/{id}
await Client.DeleteAsync("/api/app/person/DeletePhone?id=" + douglas.Id + "&phoneId=" + firstPhone.Id);
await Client.DeleteAsync($"/api/app/person/{douglas.Id}/Phone?phoneId=" + firstPhone.Id);
douglas = _personRepository.GetList().First(p => p.Name == "Douglas");
douglas.Phones.Any(p => p.Id == firstPhone.Id).ShouldBeFalse();

2
test/Volo.Abp.TestApp.Tests/Volo/Abp/TestApp/Application/PersonAppService_Tests.cs

@ -18,7 +18,7 @@ namespace Volo.Abp.TestApp.Application
[Fact]
public async Task GetAll()
{
var people = await _personAppService.GetAll(new PagedAndSortedResultRequestDto());
var people = await _personAppService.GetList(new PagedAndSortedResultRequestDto());
people.Items.Count.ShouldBeGreaterThan(0);
}
}

Loading…
Cancel
Save