我正在尝试使用定义良好的模型为定义良好的Web API构建LINQ提供程序。我正在关注这些演练:
在返回单个对象和多个对象时,我很难让它工作。我将解释:
最初在通过id进行查询时,显然返回一个结果它运行得很好但是,当运行一个返回对象集合的查询时,我会得到一个异常。
我做了一些更改,现在它在返回一个对象集合时效果很好,但在按id运行查询时抛出了与以前相同的异常。
我目前拥有的代码(适用于多个结果)如下:
自定义查询提供程序
public override object Execute(Expression expression)
{
SetSecurityToken();
var elementType = TypeSystem.GetElementType(expression.Type);
var elementTypeCollection = typeof (IEnumerable<>).MakeGenericType(elementType);
var task = GetResult(expression, elementType);
var resultProperty = typeof(Task<>).MakeGenericType(elementTypeCollection).GetProperty("Result");
//WHEN IF FAILS IT DOES SO HERE!
var result = resultProperty.GetValue(task);
return result;
}
private Task GetResult(Expression expression, Type elementType)
{
var requestUrl = Translate(expression);
var method = _httpRequest.GetType().GetMethod("GetHttpRequest").MakeGenericMethod(new[] { elementType });
var task = (Task) method.Invoke(_httpRequest, new object[] { requestUrl, _securityToken, null });
return task;
}
我有一个包装来自HttpClient的调用的类。 Get方法如下所示:
public async Task<IEnumerable<T>> GetHttpRequest<T>(string apiPath, string token, string contentType = null)
{
using (var client = GetHttpClient(true, contentType))
{
var formattedPath = FormatPathWith(apiPath, token);
var response = await client.GetAsync(formattedPath);
var result = response.IsSuccessStatusCode && contentType == null
? await response.Content.ReadAsAsync<IEnumerable<T>>()
: default(IEnumerable<T>);
return result;
}
}
如果我删除所有IEnumerable&lt;&gt;引用然后它适用于单个对象结果。它看起来像这样:
查询提供商
public override object Execute(Expression expression)
{
SetSecurityToken();
var elementType = TypeSystem.GetElementType(expression.Type);
var task = GetResult(expression, elementType);
var resultProperty = typeof(Task<>).MakeGenericType(elementType).GetProperty("Result");
//WHEN IF FAILS IT DOES SO HERE!
var result = resultProperty.GetValue(task);
return result;
}
private Task GetResult(Expression expression, Type elementType)
{
var requestUrl = Translate(expression);
var method = _httpRequest.GetType().GetMethod("GetHttpRequest").MakeGenericMethod(new[] { elementType });
var task = (Task) method.Invoke(_httpRequest, new object[] { requestUrl, _securityToken, null });
return task;
}
HTTP包装器
public async Task<T> GetHttpRequest<T>(string apiPath, string token, string contentType = null)
{
using (var client = GetHttpClient(true, contentType))
{
var formattedPath = FormatPathWith(apiPath, token);
var response = await client.GetAsync(formattedPath);
var result = response.IsSuccessStatusCode && contentType == null
? await response.Content.ReadAsAsync<T>()
: default(T);
return result;
}
}
在这两种情况下抛出的异常是:
{&#34;无法将当前JSON数组(例如[1,2,3])反序列化为类型 &#39; LinqProvider.Model.Project&#39;因为类型需要JSON对象 (例如{\&#34; name \&#34;:\&#34; value \&#34;})要正确反序列化。解决这个问题 错误要么将JSON更改为JSON对象(例如, {\&#34; name \&#34;:\&#34; value \&#34;})或将反序列化类型更改为数组或 实现集合接口的类型(例如ICollection,IList) 像可以从JSON数组反序列化的List。 JsonArrayAttribute也可以添加到类型中以强制它 从JSON数组反序列化。路径&#39;&#39;,第1行,第1位。&#34;}
我正在使用JSON.Net来处理json序列化,但我不认为它可能与此相关,因为我不需要更改对象的属性来查看行为的差异,当然我可以错了。
感谢您的帮助。
答案 0 :(得分:0)
结果证明问题在于,根据从Web API检索对象的方式,JSON将是单个对象或对象数组,并且在查询提供程序上显示此行:
var elementType = TypeSystem.GetElementType(expression.Type);
表示硬编码为IEnumerable或T的对象的预期类型。
幸运的是,从已翻译的表达式(要调用的URL)中我可以确定可以预期的内容,例如,如果搜索是通过'Id'完成的,我可以期待单个对象或者任何单词'all' ,'搜索','拥有'被发现是一个集合是可以预期的。
所以最终解决方案看起来像这样:
public override object Execute(Expression expression)
{
var translatedExpression = Translate(expression);
SetAdminSecurityToken();
var elementType = GetElementType(expression);
var task = GetResultFrom(elementType, translatedExpression);
var resultProperty = typeof(Task<>).MakeGenericType(elementType).GetProperty("Result");
var result = resultProperty.GetValue(task);
return GetReturnValue(result, elementType);
}
private Type GetElementType(Expression expression)
{
var elementType = TypeSystem.GetElementType(expression.Type);
//The IsMultipleResults property on the translator encapsulates the
//logic mentioned in the answer description.
return _queryTranslator.IsMultipleResults ? typeof(IEnumerable<>).MakeGenericType(elementType) : elementType;
}
private Task GetResultFrom(Type elementType, string translatedExpression)
{
var securityToken = _queryTranslator.UseUserToken
? GetSecurityToken(_queryTranslator.UserEmail, _queryTranslator.UserPassword)
: _securityToken;
var method = _httpRequest.GetType().GetMethod("GetHttpRequest").MakeGenericMethod(new[] { elementType });
var task = (Task)method.Invoke(_httpRequest, new object[] { translatedExpression, securityToken, null });
return task;
}
在这种情况下,我可以根据翻译过的URL中的一些关键词确定类型,但重要的是,只要可以通过某种方式确定,我可以将预期类型设置为单个T或IEnumerable。 / p>
希望这对某些人有用。