public Task<IServiceResponse<int>> InsertMyObject(IServiceRequest<MyObject> obj) { obj.MustNotBeNull("obj"); return Task.Factory.StartNew(() => { using (var repo = new ExampleRepo()) { var toInsert = Mapper.Map<MyEntity>(obj.Argument); try { repo.MyEntities.Insert(toInsert); } catch (Exception ex) { //yes - catching all exceptions is not good - but this is just demonstrating how you might use the exception to //generate a failed response that automatically has the exception on it. //IN SOME CASES, your service layer operations will bubble their exceptions out, of course - it all depends //on how you want to handle it. return ex.AsFailedResponse<int>(); } return toInsert.Id.AsSuccessfulResponse(); } }); }
public async System.Threading.Tasks.Task<IServiceResponse<MyObject>> GetMyObject(IServiceRequest<int> id) { // so we use the same validation mechanism that's used over in the Direct service implementation in // ../WebAPIDemos.ServiceLayer.Direct/MyObjectService.cs id.MustNotBeNull("id"); //note - I'm using await here to handle the implicit casting of ApiServiceResponse<T> to IServiceResponse<T> return await _requestManager.Get<ApiServiceResponse<MyObject>>(string.Format("api/MyObjects/{0}", id.Argument.ToString()), id); }
//note - for testability - a better implementation of this service would accept an IServiceCache abstraction //(name is actually irrelevant - it'd be a proprietary type for this solution), //and then one implementation of that would operate over the HostingEnvironment.Cache; making it //possible to isolate this class in a unit test with a mocked IServiceCache implementation. public async System.Threading.Tasks.Task<IServiceResponse<MyObject>> GetMyObject(IServiceRequest<int> id) { id.MustNotBeNull("id"); string cacheKey = MyObjectCacheKey(id.Argument); //do caching MyObject cached = (MyObject)HostingEnvironment.Cache[cacheKey]; if (cached != null) return cached.AsSuccessfulResponse(); //try and retrieve the object from the inner service. The logic here is if we get a successful response, then //we will cache it. Otherwise we will simply return the response. So, crucially, failed lookups are never cached in //this implementation - which, in practise, might not be desirable. var response = await _inner.GetMyObject(id); if (response.Success) HostingEnvironment.Cache.Insert(cacheKey, response.Result, null, DateTime.UtcNow.AddMinutes(5), System.Web.Caching.Cache.NoSlidingExpiration); return response; }
public Task<IServiceResponse<MyObject>> GetMyObject(IServiceRequest<int> id) { id.MustNotBeNull("id"); MyObject foo = null; //return Task.FromResult(foo.AsSuccessfulResponse()); return Task.Factory.StartNew(() => { using (var repo = new ExampleRepo()) { var found = Mapper.Map<MyObject>(repo.MyEntities.Fetch(id.Argument)); if (found != null) return found.AsSuccessfulResponse(); else //could be nicer - ideally want a 'AsResponse' method that will auto-select success/fail based on not-null/null return found.AsFailedResponse(); } }); }
public async System.Threading.Tasks.Task<IServiceResponse<PagedResult<MyObject>>> QueryMyObjects(IServiceRequest<PagedQuery> query) { query.MustNotBeNull("query"); //this method of query strings from object content can be refactored. However, it will have to be a more complex solution //that is completely generic and handles nested objects in the same way that the server libraries expect to see. //for now, this merely demonstrates the core principle. Dictionary<string, string> queryKeyValues = new Dictionary<string, string>(); //some system that relies on a similar mechanism to Model Binding should be used to convert to strings. That uses //the TypeDescriptor.GetConverter mechanism, so we couuld do the same. queryKeyValues["Page"] = Convert.ToString(query.Argument.Page); queryKeyValues["PageSize"] = Convert.ToString(query.Argument.PageSize); string queryString = null; using (var tempContent = new FormUrlEncodedContent(queryKeyValues)) { //why use this? It handles the url encoding - and doesn't require System.Web (another popular //solution uses HttpUtility.ParseQueryString - but client code has no business referencing System.Web). queryString = await tempContent.ReadAsStringAsync(); } return await _requestManager.Get<ApiServiceResponse<PagedResult<MyObject>>>(string.Concat("api/MyObjects?", queryString), query); }
public async System.Threading.Tasks.Task<IServiceResponse<int>> InsertMyObject(IServiceRequest<MyObject> obj) { obj.MustNotBeNull("obj"); return await _requestManager.Send<MyObject, ApiServiceResponse<int>>("api/MyObjects", HttpMethod.Post, obj); }
public Task<IServiceResponse<PagedResult<MyObject>>> QueryMyObjects(IServiceRequest<PagedQuery> query) { query.MustNotBeNull("query"); //just showing another way of 'faking' a task when there's no asynchrony actually involved: using (var repo = new ExampleRepo()) { if (query.Argument.PageSize == -1) //get all { var all = repo.MyEntities.All().ToArray(); var result = new PagedResult<MyObject>() { Count = all.Length, Page = 1, PageCount = 1, PageResults = Mapper.Map<MyEntity[], MyObject[]>(all), TotalCount = all.Length }.AsSuccessfulResponse(); return Task.FromResult(result); } else { var total = repo.MyEntities.All().Count(); //to do - should be doing a bit more validation here... var page = repo.MyEntities.All().Skip((query.Argument.Page - 1) * query.Argument.PageSize).Take(query.Argument.PageSize).ToArray(); var result = new PagedResult<MyObject>() { TotalCount = total, Page = query.Argument.Page, Count = page.Length, PageCount = (int)Math.Round(((decimal)total / query.Argument.PageSize) + 0.5M), PageResults = Mapper.Map<MyEntity[], MyObject[]>(page) }.AsSuccessfulResponse(); return Task.FromResult(result); } } }