作为一个例子,我有一个简单的web api,它有一个名为ParentsController的控制器,它是一个标准的WebAPi2 ApiController。它是锅炉板。
在客户端,我创建了一个Repository Base类,基于它我有一个ParentRepository类。
ApiRequester:
public class ApiRequester
{
readonly Uri _apiServiceBaseAddress;
readonly String _apiControllerPath;
readonly Guid _apiKey;
public ApiRequester(string apiServiceBaseAddress, string apiControllerPath, Guid apiKey)
{
_apiServiceBaseAddress = new Uri(apiServiceBaseAddress);
_apiControllerPath = apiControllerPath;
_apiKey = apiKey;
}
public async Task<T> Get<T>(string queryParameters)
{
using (var client = new HttpClient { BaseAddress = _apiServiceBaseAddress })
{
//client.Timeout = TimeSpan.FromSeconds(60);
client.DefaultRequestHeaders.Add("X-APIKey", _apiKey.ToString());
var response = await client.GetAsync(_apiControllerPath + queryParameters);
var result = await response.Content.ReadAsAsync<T>();
return result;
}
}
public async Task<T> Post<T>(string queryParameters, T entity)
{
using (var client = new HttpClient { BaseAddress = _apiServiceBaseAddress })
{
client.DefaultRequestHeaders.Add("X-APIKey", _apiKey.ToString());
HttpResponseMessage response = null;
response = await client.PostAsJsonAsync<T>(_apiControllerPath + queryParameters, entity);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsAsync<T>();
return result;
}
}
public async Task<T> Put<T>(string queryParameters, T entity)
{
using (var client = new HttpClient { BaseAddress = _apiServiceBaseAddress })
{
client.DefaultRequestHeaders.Add("X-APIKey", _apiKey.ToString());
var response = await client.PutAsJsonAsync<T>(_apiControllerPath + queryParameters, entity);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsAsync<T>();
return result;
}
}
public async Task Delete(string queryParameters)
{
using (var client = new HttpClient { BaseAddress = _apiServiceBaseAddress })
{
client.DefaultRequestHeaders.Add("X-APIKey", _apiKey.ToString());
var response = await client.DeleteAsync(_apiControllerPath + queryParameters);
response.EnsureSuccessStatusCode();
}
}
}
RepositoryBase:
public abstract class RepositoryBase<T> where T : class, IEntity
{
readonly ApiRequester _requester;
protected RepositoryBase(string apiBaseUri, string controllerPath, Guid apiKey)
{
if (String.IsNullOrWhiteSpace(apiBaseUri))
throw new ArgumentNullException("apiBaseUri");
if (apiKey.Equals(default(Guid)))
throw new ArgumentNullException("apiKey");
_requester = new ApiRequester(apiBaseUri, controllerPath, apiKey);
}
public virtual Task<ICollection<T>> GetAsync(string queryParameters)
{
return _requester.Get<ICollection<T>>(queryParameters);
}
public virtual Task<T> PostAsync(string queryParameters, T entity)
{
return _requester.Post<T>(queryParameters, entity);
}
public virtual Task<T> PutAsync(string queryParameters, T entity)
{
return _requester.Put<T>(queryParameters, entity);
}
public virtual Task DeleteAsync(string queryParameters)
{
return _requester.Delete(queryParameters);
}
}
ParentRepository:
public class ParentRepository : RepositoryBase<Parent>
{
public ChannelRepository(string apiBaseUri, string controllerPath, Guid apiKey)
: base(apiBaseUri, controllerPath, apiKey)
{ }
}
因此,客户的消费者可以拨打电话从API获取父母列表:
pRepo = new ParentRepository();
var parents = await pRepo.GetAsync();
// Do something with parent collection.
Parent实体如下所示:
public class Parent : IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ParentId { get; set; }
public String Name { get; set; }
// Navigation Properties
public virtual ICollection<Child> Children { get; set; }
}
我想在我的存储库方法中允许的内容类似于以下内容:
pRepo = new ParentRepository();
var parents = await pRepo.GetAsync().Where(p => p.Name == "aName").Include(p => p.Children);
这就是我被困住的地方。
如何在GetAsync()方法中拦截这个,以便我可以构建我的http请求?
获得&#39; Where&#39;我是否创建了一个Extension方法? 类似的东西:
public static ICollection<TEntity> Where(this ICollection<TEntity> source, Func<TEntity> , bool> predicate)
{
// Do something or not?
}
但接着是什么?
对于&#39; Include&#39;部分,我在这里需要什么,也许来自System.Reflection以获取Child集合属性名称?
我如何拦截GetAsync()方法中的推理?
我知道有更简单的方法可以用重载方法做我想要的事情,但我喜欢创建类似linq的方法的想法。
编辑:
为了清楚我想要什么,我想我需要使用表达式树(不知道如何)将我的linq表达式转换为web uri:
所以在我的客户端,我写道:var parents = await pRepo.GetAsync().Where(p => p.Name == "aName").Include(p => p.Children);
并将该表达式转换为:
GET /api/parents/?name=aName&IncludeChildren=true
然后,客户端可以执行Get请求。请注意,这应该是我可以在我构建的任何客户端中使用的目标,任何类型的基于Web的API都不一定需要是WebAPI。
答案 0 :(得分:0)
在我的(有限)经验中,Web API控制器具有过滤和排序等可选参数,然后将这些参数转换为类似linq的请求到数据访问层中的Repository类。其中没有一个驻留在客户端上,客户端使用查询字符串中的标准HTTP约定向Web API控制器发出请求,例如:
GET /api/parent?minimumId=5&maximumId=20&orderBy=Name
可选的查询字符串参数可以转换为Linq或Dynamic Linq,以查询底层DAL提供的某种IQueryable。
由于控制器本质上是面向HTTP的,因此很可能不会在对Web API控制器的请求中看到类似linq的行为,而是倾向于类似HTTP的行为。
如果你真的想用类似Linq的语法包含对Web API控制器的调用,我会考虑使用Dynamic Linq将你的数据(Funcs / Expressions / Strings / etc)转换为Linq查询,因为它在至少可以让你避免自己反复思考。