예를 들어, ParentsController라는 단일 컨트롤러가있는 간단한 웹 API가 있는데, 표준 WebAPi2 ApiController입니다. 보일러 판입니다.HttpRequest 프레임웍에 Linq-To-Repository를 만드는 방법
클라이언트 측에서 나는 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에서 부모의 목록을 얻기 위해 전화를 걸 수 있습니다 :
내가 내 저장소 방법에있게하고 싶은 것은 다음과 유사한입니다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);
가 그리고 여기에 내가 끼 었어 곳
pRepo = new ParentRepository();
var parents = await pRepo.GetAsync();
// Do something with parent collection.
는 부모 엔티티는 다음과 같습니다 .
내 http 요청을 빌드 할 수 있도록 GetAsync() 메소드에서 어떻게 차단합니까?
'Where'절을 가져 오려면 확장 메서드를 만드시겠습니까? 은 다음과 같습니다.
public static ICollection<TEntity> Where(this ICollection<TEntity> source, Func<TEntity> , bool> predicate)
{
// Do something or not?
}
하지만 그 다음은 무엇입니까?
'Include'부분에는 System.Reflection에서 Child collection 속성 이름을 가져 오기 위해 무엇이 필요합니까?
다시 내 GetAsync() 메서드에서 유추를 가로채는 방법은 무엇입니까?
내가 오버로드 된 메소드를 사용하여 원하는 것을 쉽게 수행 할 수있는 방법이 있다는 것을 알고 있지만 linq와 유사한 접근법을 만드는 아이디어를 좋아합니다.
편집 :
내가 원하는 명확성을 위해와 내가 웹 URI에 내 LINQ 식을 변환 (방법을 아직 확실하지) 식 트리를 사용할 필요가 있다고 생각 :
이그렇게 내 고객에 내가 쓰기 : 다음 GET 요청을 수행 할 수 있습니다
GET /api/parents/?name=aName&IncludeChildren=true
클라이언트 : var parents = await pRepo.GetAsync().Where(p => p.Name == "aName").Include(p => p.Children);
및 그 표현이 같은 변환됩니다. 이것은 모든 클라이언트에서 사용할 수 있어야합니다. 웹 기반 API의 모든 유형을 타겟팅하는 것은 WebAPI 일 필요는 없습니다.
내 질문이 구체적이지 않을 수 있습니다. 내가 원하는 것과 연구를 통해 표현식 트리로 작업해야한다고 생각합니다. 그래도 어떻게 확신 할 수 있습니까? 변환하고 싶습니다 : pRepo = new ParentRepository(); var parents = pRepo.GetAsync()를 기다립니다. (p => p.Name == "aName"). 포함 (p => p.Children); to/api/parent? name = aName & IncludeChildren = true – John
이것은 좀 더 명확합니다. 나는 의도 된 질문에 대한 적어도 부분적인 해결책을 가지고 오늘 나의 대답을 편집하려고 노력할 것이다. – jmsb