Created
January 19, 2014 08:09
-
-
Save lnickers2004/8501845 to your computer and use it in GitHub Desktop.
WebApi 2: Implemented Post of DiaryEntries. Added a Parse method to the ModelFactory to build the DiaryEntry from the model. Return appropriate Http Status codes in success and failure cases. Updated Base api controller to pass the the repository into the ModelFactory so the model factory's new Parse() method can use the repository to get data t…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using CountingKs.Data; | |
using CountingKs.Models; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Net.Http; | |
using System.Web.Http; | |
namespace CountingKs.Controllers | |
{ | |
//make base controller abstract so it cannot be instantiated | |
//all our controllers will derive from base controller to | |
//inherit common funtionality | |
public abstract class BaseApiController : ApiController | |
{ | |
private ModelFactory _modelFactory; | |
private ICountingKsRepository _repo; | |
public BaseApiController( ICountingKsRepository repo ) | |
{ | |
_repo = repo; | |
} | |
protected ICountingKsRepository TheRepository | |
{ | |
get | |
{ | |
return _repo; | |
} | |
} | |
//KEY POINT: we need to defer the creation of the model factory until | |
// it is needed. So we create a deferred property | |
//Note: this is basically a singleton pattern.. | |
//the factory will exist for the lifetime of the controller | |
protected ModelFactory TheModelFactory | |
{ | |
//remember, we're using factory pattern to copy database entities into DTO's that contain | |
//discoverable Hyperlinks for each resource returned to the user | |
get | |
{ | |
//the first get will cause the factory to be created | |
if(_modelFactory == null) | |
{ | |
//it should be late enough for the request to not be null | |
//the model factory will be crated as a result of a user request | |
//so we can create the model factory and pass it the request so we may | |
//use it and the Url helper to generate the requested resource's URI Hyperlinks for including | |
//in the DTO that we pass back to the user | |
_modelFactory = new ModelFactory(this.Request,TheRepository); | |
} | |
return _modelFactory; | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Net.Http; | |
using System.Web.Http; | |
using CountingKs.Data; | |
using CountingKs.Services; | |
using CountingKs.Models; | |
namespace CountingKs.Controllers | |
{ | |
public class DiaryEntriesController : BaseApiController | |
{ | |
private ICountingKsIdentityService _identityService; | |
public DiaryEntriesController(ICountingKsRepository repo,ICountingKsIdentityService identityService) | |
: base(repo) | |
{ | |
_identityService = identityService; | |
} | |
//return all the diary entries for the current user on the given date | |
public IEnumerable<DiaryEntryModel> Get(DateTime diaryId) | |
{ | |
var results = TheRepository.GetDiaryEntries(_identityService.CurrentUser, diaryId) | |
.ToList() | |
.Select(e => TheModelFactory.Create(e)); | |
//NOTE: if results = null we will return empty collection | |
return results; | |
} | |
//return the specific diary entry for the current user by diary entry id | |
public HttpResponseMessage Get(DateTime diaryId, int id) | |
{ | |
var result = TheRepository.GetDiaryEntry(_identityService.CurrentUser,diaryId,id); | |
if(result == null) | |
{ | |
return Request.CreateResponse(HttpStatusCode.NotFound); | |
} | |
else | |
{ | |
return Request.CreateResponse(HttpStatusCode.OK, TheModelFactory.Create(result)); | |
} | |
} | |
public HttpResponseMessage Post( DateTime diaryId, [FromBody]DiaryEntryModel model) | |
{ | |
try | |
{ | |
var entity = TheModelFactory.Parse(model); | |
if(entity == null) | |
{ | |
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, | |
"Could not read diary entry in bode"); | |
} | |
var diary = TheRepository.GetDiary(_identityService.CurrentUser,diaryId); | |
if(diary == null) | |
{ | |
//trying to create an entry for a diary that doesn't exist | |
return Request.CreateResponse(HttpStatusCode.NotFound); | |
} | |
//add the diary entry to the diary we retrieved | |
diary.Entries.Add(entity); | |
//BUSINESS RULE | |
//MAKE SURE ITS NOT A DUPLICATE FOOD ITEM | |
if(diary.Entries.Any(e=>e.Measure.Id == entity.Measure.Id)) | |
{ | |
return Request.CreateResponse(HttpStatusCode.BadRequest, "Duplicate Measure not allowed"); | |
} | |
//SAVE THE NEW ENTRY | |
//store the updated diary with its new entry | |
//NOTE: if save fails the catch will handle it | |
if(TheRepository.SaveAll()) | |
{ | |
//Posts should always return Created upon success | |
return Request.CreateResponse(HttpStatusCode.Created, TheModelFactory.Create(entity)); | |
} | |
else | |
{ | |
return Request.CreateResponse(HttpStatusCode.BadRequest, "Could not Save to the database"); | |
} | |
} | |
catch(Exception ex) | |
{ | |
return Request.CreateErrorResponse(HttpStatusCode.BadRequest,ex); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Web; | |
using CountingKs.Data.Entities; | |
using System.Web.Http.Routing; | |
using System.Net.Http; | |
using CountingKs.Data; | |
namespace CountingKs.Models | |
{ | |
//using a Model Factory, we have only one place to handling Mapping from | |
//Database entities to DTO's | |
public class ModelFactory | |
{ | |
private UrlHelper _urlHelper; | |
private ICountingKsRepository _repo;//needed for filling entries based on input model ... see below | |
//LEN NOTE: THE REASON WE DID NOT USE AUTOMAPPER IS BECAUSE WE WANTED TO USE THE REQUEST | |
//AND THE URL HELPER TO AID US IN CREATING OUR HYPERLINKS | |
public ModelFactory( HttpRequestMessage request ,ICountingKsRepository repo) | |
{ | |
_repo = repo; | |
//Remember to use the Url helper for WebAPI | |
//which is in System.Web.Http.Routing | |
_urlHelper = new UrlHelper(request); //this will help us to build | |
//the URLs for developer API discovery | |
} | |
public FoodModel Create( Food food ) | |
{ | |
return new FoodModel() | |
{ | |
//get an url for the Food roud and supply the id of the food that we're returning | |
Url = _urlHelper.Link("Food", new { foodid = food.Id }), | |
Description = food.Description, | |
Measures = food.Measures.Select(m => Create(m)) | |
}; | |
} | |
public MeasureModel Create( Measure measure ) | |
{ | |
return new MeasureModel() | |
{ | |
Url = _urlHelper.Link("Measures", new { foodid = measure.Food.Id, id = measure.Id }), | |
Description = measure.Description, | |
Calories = Math.Round(measure.Calories) | |
}; | |
} | |
public DiaryModel Create( Diary d ) | |
{ | |
return new DiaryModel() | |
{ | |
//NOTE: IMPORTANT, we are not using the Id property for the diary ID | |
//we are using the created date, or current date. There will be one diary per day per user. | |
//We need to insure that only one diary exists per user for any given date!!! We will do that | |
//elsewhere. We will assume that the database has unique constraint set on this field also | |
Url = _urlHelper.Link("Diaries", new { diaryid = d.CurrentDate.ToString("yyyy-MM-dd") }), | |
CurrentDate = d.CurrentDate, | |
Entries = d.Entries | |
.ToList() | |
.Select(e => Create(e)) | |
}; | |
} | |
public DiaryEntryModel Create( DiaryEntry e ) | |
{ | |
return new DiaryEntryModel() | |
{ | |
Url = _urlHelper.Link("DiaryEntries", new { diaryid = e.Diary.CurrentDate.ToString("yyyy-MM-dd"), id=e.Id }), | |
FoodDescription = e.FoodItem.Description, | |
MeasureDescription = e.Measure.Description, | |
MeasureUrl = _urlHelper.Link("Measures", new { foodid = e.Measure.Food.Id, id = e.Measure.Id }), | |
Quantity= e.Quantity | |
}; | |
} | |
//create a diary entry from the input model | |
public DiaryEntry Parse( DiaryEntryModel model ) | |
{ | |
try | |
{ | |
var entry = new DiaryEntry(); | |
//did user set the quantity? | |
if(model.Quantity != default(double)) | |
{ | |
entry.Quantity= model.Quantity; | |
} | |
var uri = new Uri(model.MeasureUrl); | |
//get id from the measureUrl passed via the model | |
//if parsing fails we'll be catching the exception and returning a null DiaryEntry | |
var measureId = int.Parse(uri.Segments.Last()); | |
var measure =_repo.GetMeasure(measureId); | |
entry.Measure = measure; | |
entry.FoodItem = measure.Food; | |
return entry; | |
} | |
catch(Exception) | |
{ | |
//the caller can test for null to see if parsing failed | |
return null; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
implemented a simple business rule to disallow creating duplicate measures for a given day's diary entry