Created
January 18, 2014 07:59
-
-
Save lnickers2004/8487619 to your computer and use it in GitHub Desktop.
WebApi2: Added a Diary Controller which uses an Identity Service for authorization to return logged-in user's private daily diary. also added testing to ensure a diary is found and return the apropriate HttpReponse Codes-- either 200 OK or 404 not found. Also have special case code for returning a date as part of the URI (making use of string fo…
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; | |
namespace CountingKs.Services | |
{ | |
public class CountingKsIdentityService : CountingKs.Services.ICountingKsIdentityService | |
{ | |
public CountingKsIdentityService() | |
{ | |
} | |
public string CurrentUser | |
{ | |
get | |
{ | |
//hard-coded username for now since it is in the database | |
return "shawnwildermuth"; | |
} | |
} | |
} | |
} |
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.Data.Entities; | |
using CountingKs.Models; | |
using CountingKs.Services; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Net.Http; | |
using System.Threading; | |
using System.Web.Http; | |
namespace CountingKs.Controllers | |
{ | |
public class DiariesController : BaseApiController | |
{ | |
private ICountingKsIdentityService _identityService; | |
//We have opted to create and use a user Identity service and we'll inject it | |
//into the controller. We didn't inject it into the BaseApiController because | |
//the Food and Measures don't require identity checking. Only the personal | |
//part of the api e.g. Diaries require Authentication) SOLID Principle | |
//Interface Segregation Principle (Don't force other classed to take dependencies | |
// that they do not need!!) | |
//If we wish, we could create another BaseApiController with Identity | |
//e.g. BaseWithIdentityApiController, then we could inject the Indentity Service into that | |
//base api controller and derive form it instead. But for simplicity, we won't don that now | |
public DiariesController( ICountingKsRepository repo, | |
ICountingKsIdentityService identityService ) | |
: base(repo) | |
{ | |
_identityService = identityService; | |
} | |
public IEnumerable<DiaryModel> Get() | |
{ | |
//using Thread.CurrentPrincipal to get the user is not very testable | |
//var username = Thread.CurrentPrincipal.Identity.Name; | |
var username = _identityService.CurrentUser; | |
var results = TheRepository.GetDiaries(username) | |
.OrderByDescending(d => d.CurrentDate) | |
.Take(10) | |
.ToList() | |
.Select(d => TheModelFactory.Create(d)); | |
return results; | |
} | |
//here is a special case: if the diary doesn't exist we | |
// want to return a result of not found | |
public HttpResponseMessage Get( DateTime diaryId ) | |
{ | |
var username = _identityService.CurrentUser; | |
//NOTE: GetDiary method expects a DateTime | |
var result = TheRepository.GetDiary(username, diaryId); | |
if(result == null) | |
{ | |
//Always return results or not found. never return empty results. that is not useful | |
return Request.CreateResponse(HttpStatusCode.NotFound); | |
} | |
else | |
{ | |
//the result diary will be serialized into the body of the reponse and the | |
// status code will be set to ok | |
return Request.CreateResponse(HttpStatusCode.OK, TheModelFactory.Create(result)); | |
} | |
} | |
} | |
} |
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.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; } | |
} | |
} |
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; | |
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 = TheFactory.Create( d.Entries | |
}; | |
} | |
public ICollection<DiaryEntry> Entries { get; set; } | |
} | |
} |
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; | |
namespace CountingKs.Services | |
{ | |
public interface ICountingKsIdentityService | |
{ | |
string CurrentUser { get; } | |
} | |
} |
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.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 } | |
); | |
// 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