Skip to content

Instantly share code, notes, and snippets.

@lnickers2004
Last active January 3, 2016 18:19
Show Gist options
  • Save lnickers2004/8501299 to your computer and use it in GitHub Desktop.
Save lnickers2004/8501299 to your computer and use it in GitHub Desktop.
WebApi 2: Add DiaryEntriesController and implement Gets Diary Entries using IdentityService, Repository, ModelFactory
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);
}
return _modelFactory;
}
}
}
}
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));
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CountingKs.Data.Entities
{
public class DiaryEntry
{
public int Id { get; set; }
public Food FoodItem { get; set; }
public Measure Measure { get; set; }
public double Quantity { get; set; }
public virtual Diary Diary { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CountingKs.Models
{
public class DiaryEntryModel
{
public string Url { get; set; }
public string FoodDescription;
public string MeasureDescription;
public string MeasureUrl;
public double Quantity;
}
}
using CountingKs.Data.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CountingKs.Models
{
public class DiaryModel
{
public string Url { get; set; }
public DateTime CurrentDate;
public IEnumerable<DiaryEntryModel> Entries { get; set; }
}
}
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;
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;
//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 )
{
//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
};
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Formatting;
using System.Web.Http;
using Newtonsoft.Json.Serialization;
namespace CountingKs
{
public static class WebApiConfig
{
public static void Register( HttpConfiguration config )
{
config.Routes.MapHttpRoute(
name: "Food",
//routeTemplate: "api/foods/{foodid}",
routeTemplate: "api/v1/nutrition/foods/{foodid}",
defaults: new { controller = "foods", foodid = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "Measures",
routeTemplate: "api/v1/nutrition/foods/{foodid}/measures/{id}",
defaults: new { controller = "measures", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "FoodOrig",
routeTemplate: "api/nutrition/foodsOrig/{foodid}",
defaults: new { controller = "foodsOrig", foodid = RouteParameter.Optional }
);
//setting up a route to return diaries for the current logged in user
//LEN Note: we will secure the api and use that info to get the logged user
//we did not have to pass the user's id since we're dealing with logger in user
config.Routes.MapHttpRoute(
name: "Diaries",
routeTemplate: "api/user/diaries/{diaryid}",
defaults: new { controller = "diaries", diaryid = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DiaryEntries",
routeTemplate: "api/user/diaries/{diaryid}/entries/{id}",
defaults: new { controller = "diaryentries", id = RouteParameter.Optional }
);
// Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
// To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
// For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
//LEN NOTE:
//config.EnableQuerySupport();//optional support to expose an iqueryable endpoint for
//ODATA feeds for line of business that is Microsoft centric
//so we don't do this we don't support querying over the wire
//we will instead build a standard restful api that returns
//standard json or xml
//add camel casing
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().FirstOrDefault();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment