Web API, OData, $inlinecount и тестирование
Ранее у меня был контроллер Web API, который выглядел так:
public IQueryable<ApiDesignOverview> GetList(
string brandIds = "",
string categoryIds = "",
string query = "",
string categoryOp = "or")
Я слышал, что пакет OData NuGet теперь поддерживает параметр OData $ inlinecount, поэтому я попытался добавить его, используя инструкции из http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options - я не хочу использовать OData оптом, так как это повлечет за собой большую ре-архитектуру приложения, поэтому я остановился на PageResult<T>
вариант.
Итак, теперь мой контроллер выглядит так:
public PageResult<ApiDesignOverview> GetList(
ODataQueryOptions<ApiDesignOverview> options,
string brandIds = "",
string categoryIds = "",
string query = "",
string categoryOp = "or")
Мои проблемы сейчас:
- Как мне издеваться над ODataQueryOptions для модульного тестирования?
- Если их нельзя высмеять, как мне их создать? мне нужно
ODataQueryContext
построить тот, который требуетMicrosoft.Data.Edm.IEdmModel
что требует... что? Я не могу найти никакой документации для этого.
Действительно, было бы лучше, если бы я мог удалить ODataQueryOptions из подписи контроллера, как и раньше. Это возможно?
3 ответа
Если вы предпочитаете возвращать IQueryable и хотите получить поддержку $inlinecount, это все еще возможно сделать, изменив QueryableAttribute.
public class InlineCountQueryableAttribute : QueryableAttribute
{
private static MethodInfo _createPageResult =
typeof(InlineCountQueryableAttribute)
.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
.Single(m => m.Name == "CreatePageResult");
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
HttpRequestMessage request = actionExecutedContext.Request;
HttpResponseMessage response = actionExecutedContext.Response;
IQueryable result;
if (response.IsSuccessStatusCode
&& response.TryGetContentValue<IQueryable>(out result))
{
long? inlineCount = request.GetInlineCount();
if (inlineCount != null)
{
actionExecutedContext.Response = _createPageResult.MakeGenericMethod(result.ElementType).Invoke(
null, new object[] { request, request.GetInlineCount(), request.GetNextPageLink(), result }) as HttpResponseMessage;
}
}
}
internal static HttpResponseMessage CreatePageResult<T>(HttpRequestMessage request, long? count, Uri nextpageLink, IEnumerable<T> results)
{
return request.CreateResponse(HttpStatusCode.OK, new PageResult<T>(results, nextpageLink, count));
}
}
Обратите внимание, что я использую отражение для создания PageResult. Вместо этого вы можете вернуть понравившийся вам объект, который можно отформатировать с помощью используемого вами средства форматирования. Анонимный объект с результатами и количеством будет работать, если вы используете форматер Json.
Если вы не хотите (или не можете, как в моем случае) отказаться от использования ODataQueryOptions и PageResult, вот как вы можете создать экземпляр ODataQueryOptions для модульных тестов:
//arrange
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/MyProject/api/Customers?$filter=CustomerID eq 1");
var controller = new CustomersController
{
Request = request
};
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Customer>("Customers");
var opts = new ODataQueryOptions<Customer>(new ODataQueryContext(modelBuilder.GetEdmModel(),typeof(Customer)), request);
//act
var result = controller.Get(opts);
//assert
Assert.AreEqual(1, result.Items.First().CustomerID);
В последнем ODataController
есть AllowedQueryOptions
это решает это.
public class MyOdataController : ODataController
{
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<Product> Get()
{
return Products.AsQueryable();
}
}