Tips and Tricks in a world of Mix

Posts tagged ‘solution structure’

SPA 4–Camper Camper– Surfacing JSON Data with ASP.NET Web API Code – JOHN PAPA

You can check out the series of the posts on the subject

<—SPA 3– Data Models, Entity Framework, and Data Patterns

SPA 5– Code Camper – Web Optimization—>

image

 

image

 

image

image

image

 

Routing

 

image

 

 

image

 

image

image

   1:  

   2: routes.MapHttpRoute( 

   3:  name: 

   4:  ControllerAction, 

   5:  routeTemplate: 

   6:  "api/{controller}/{action}"

   7:  );

 

APIController GET

 

The ApiController offers you an automatic functionality matched to EF UoW structure playing nicely together ! You’’ll most likely create a base with UoW property that will be inherited in every controller .

You can add Json Viewer to Chrome for a better reading.

The Ioc is coming into play when the ICodeCamperUow initializes each controller constructor matched to concrete type of Model Entity.

 

 

We’ve seen the actual class – it sums up the repository interfaces of the whole system

so it will be only one Interface to pass through as a promiss to constructors

   1: public class CodeCamperUow : ICodeCamperUow, IDisposable

   2:   {

   3:       public CodeCamperUow(IRepositoryProvider repositoryProvider)

   4:       {

   5:           CreateDbContext();

   6:  

   7:           repositoryProvider.DbContext = DbContext;

   8:           RepositoryProvider = repositoryProvider;       

   9:       }

  10:  

  11:       // Code Camper repositories

  12:  

  13:       public IRepository<Room> Rooms { get { return GetStandardRepo<Room>(); } }

  14:       public IRepository<TimeSlot> TimeSlots { get { return GetStandardRepo<TimeSlot>(); } }

  15:       public IRepository<Track> Tracks { get { return GetStandardRepo<Track>(); } }

  16:       public ISessionsRepository Sessions { get { return GetRepo<ISessionsRepository>(); } }

  17:       public IPersonsRepository Persons { get { return GetRepo<IPersonsRepository>(); } }

  18:       public IAttendanceRepository Attendance { get { return GetRepo<IAttendanceRepository>(); } }

 

 

Pay attention that the special Repositories For Persons , Sessions and Atrtendace also entered the ICodeCamperUow.

 

Also we could have changed the Implementation to a mock implementation for debugging purposes if needed and we’re getting Disposable at the base.

 

Here we have three classes handling the connectivity and registration of the Model per Interfaces throughout the project.

   1: public class IocConfig

   2:    {

   3:        public static void RegisterIoc(HttpConfiguration config)

   4:        {

   5:            var kernel = new StandardKernel(); // Ninject IoC

   6:  

   7:            // These registrations are "per instance request".

   8:            // See http://blog.bobcravens.com/2010/03/ninject-life-cycle-management-or-scoping/

   9:  

  10:            kernel.Bind<RepositoryFactories>().To<RepositoryFactories>()

  11:                .InSingletonScope();

  12:  

  13:            kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();

  14:            kernel.Bind<ICodeCamperUow>().To<CodeCamperUow>();

  15:  

  16:            // Tell WebApi how to use our Ninject IoC

  17:            config.DependencyResolver = new NinjectDependencyResolver(kernel);

  18:        }

  19:    }

 

 

Those two are standard development taken by John Papa from Microsoft Dev Team.

   1: public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver

   2:   {

   3:       private IKernel kernel;

   4:  

   5:       public NinjectDependencyResolver(IKernel kernel)

   6:           : base(kernel)

   7:       {

   8:           this.kernel = kernel;

   9:       }

  10:  

  11:       public IDependencyScope BeginScope()

  12:       {

  13:           return new NinjectDependencyScope(kernel.BeginBlock());

  14:       }

  15:   }

 
 
 
   1: public class NinjectDependencyScope : IDependencyScope

   2:     {

   3:         private IResolutionRoot resolver;

   4:  

   5:         internal NinjectDependencyScope(IResolutionRoot resolver)

   6:         {

   7:             Contract.Assert(resolver != null);

   8:  

   9:             this.resolver = resolver;

  10:         }

  11:  

  12:         public void Dispose()

  13:         {

  14:             var disposable = resolver as IDisposable;

  15:             if (disposable != null)

  16:                 disposable.Dispose();

  17:  

  18:             resolver = null;

  19:         }

  20:  

  21:         public object GetService(Type serviceType)

  22:         {

  23:             if (resolver == null)

  24:                 throw new ObjectDisposedException("this", "This scope has already been disposed");

  25:  

  26:             return resolver.TryGet(serviceType);

  27:         }

  28:  

  29:         public IEnumerable<object> GetServices(Type serviceType)

  30:         {

  31:             if (resolver == null)

  32:                 throw new ObjectDisposedException("this", "This scope has already been disposed");

  33:  

  34:             return resolver.GetAll(serviceType);

  35:         }

  36:     }

 

LookupsController –

   1: [ActionName("tracks")]

   2:        public IEnumerable<Track> GetTracks()

You are renaming the functions names to something shorter and easier

 

You can add the right route for it –

image

the trouble is that

   1: routes.MapHttpRoute(

   2:                name: ControllerAndId,

   3:                routeTemplate: "api/{controller}/{id}",

   4:               defaults: new { id = RouteParameter.Optional } 

   5:               

   6:            );

matches any parameter.

 

the most basic route – like call for speakers

   1: // This controller-per-type route is ideal for GetAll calls.

   2:            // It finds the method on the controller using WebAPI conventions

   3:            // The template has no parameters.

   4:            //

   5:            // ex: api/sessionbriefs

   6:            // ex: api/sessions

   7:            // ex: api/persons

   8:            routes.MapHttpRoute(

   9:                name: ControllerOnly,

  10:                routeTemplate: "api/{controller}"

  11:            );

 

we’ll change the original one to match only the digits and another route to match actions specifically , digits parameter only by regex

   1: //  ex: api/sessions/1

   2:           //  ex: api/persons/1

   3:           routes.MapHttpRoute(

   4:               name: ControllerAndId,

   5:               routeTemplate: "api/{controller}/{id}",

   6:               defaults: null, //defaults: new { id = RouteParameter.Optional } //,

   7:               constraints: new { id = @"^\d+$" } // id must be all digits

   8:           );

 

and the last will work with action names that we’ve defined.

   1: // This RPC style route is great for lookups and custom calls

   2:            // It matches the {action} to a method on the controller 

   3:            //

   4:            // ex: api/lookups/all

   5:            // ex: api/lookups/rooms

   6:            routes.MapHttpRoute(

   7:                name: ControllerAction,

   8:                routeTemplate: "api/{controller}/{action}"

   9:            );

 

Attention – John papa has closed the default route of MVC all together.

 

APIController  PUT

image

We can test our put method by fiddler

In fiddler you get the JSON from the Get Method 

http://localhost:52692/api/persons/3

, that in Composer change to the right URI and change the method to PUT 

http://localhost:52692/api/persons

In Request Header we will add the type of the data we send

Content-Type:application/json; charset=utf-8

In the Request Body I’ve just changed Papa to PAPA

 

image

 

When Executed we can see that the data has changed

image

204 code – co content returned as we defined

And the Data changed as I put it in..

 

 

Testing WebAPI Requests with Qunit 

image

 

Qunit – in NuGet it’s “ qunit for ASP.NET MVC

qunit gives you the opportunity to test the Web API , sending and receiving data from client .

It’s a specific testing per every scenario.

  QUnit.testSuites can run all of the tests together which can be very helpful.

 

Testing Model Validation and Other Customization

 

   1: public static class GlobalConfig

   2:     {

   3:         public static void CustomizeConfig(HttpConfiguration config)

   4:         {

   5:             // Remove Xml formatters. This means when we visit an endpoint from a browser,

   6:             // Instead of returning Xml, it will return Json.

   7:             // More information from Dave Ward: http://jpapa.me/P4vdx6

   8:             config.Formatters.Remove(config.Formatters.XmlFormatter);

   9:  

  10:             // Configure json camelCasing per the following post: http://jpapa.me/NqC2HH

  11:             // Here we configure it to write JSON property names with camel casing

  12:             // without changing our server-side data model:

  13:             var json = config.Formatters.JsonFormatter;

  14:             json.SerializerSettings.ContractResolver =

  15:                 new CamelCasePropertyNamesContractResolver();

  16:  

  17:             // Add model validation, globally

  18:             config.Filters.Add(new ValidationActionFilter());

  19:         }

  20:     }

 

json.SerializerSettings.ContractResolver =

    new CamelCasePropertyNamesContractResolver();

will allow to translate the Camel case between server and client so that at client the Upper case won’t be needed.

 

config.Formatters.Remove(config.Formatters.XmlFormatter);

will allow JSON format response.

 

   1: public class ValidationActionFilter : ActionFilterAttribute 

   2:   { 

   3:       public override void OnActionExecuting(HttpActionContext context) 

   4:       { 

   5:           var modelState = context.ModelState; 

   6:           if (!modelState.IsValid) 

   7:           { 

   8:               var errors = new JObject(); 

   9:               foreach (var key in modelState.Keys) 

  10:               { 

  11:                   var state = modelState[key]; 

  12:                   if (state.Errors.Any()) 

  13:                   { 

  14:                       errors[key] = state.Errors.First().ErrorMessage; 

  15:                   } 

  16:               } 

  17:  

  18:               context.Response = context.Request.CreateResponse<JObject>(HttpStatusCode.BadRequest, errors); 

  19:           } 

  20:       } 

  21:   }

  22: }

 

Summary

image

You can check out the series of the posts on the subject

<—SPA 3– Data Models, Entity Framework, and Data Patterns

SPA 5– Code Camper – Web Optimization—>

SPA 2–JOHN PAPA– Technologies and Patterns of the Code Camper SPA

You can check out the series of the posts on the subject

<—SPA 1.1. Getting Code Camper Started

SPA 3– Data Models, Entity Framework, and Data Patterns –>

 

Exploring the Solution Structure

Data Project

  • Global Conventions at the configuration folder ( c# fluent EF definitions)
  • DBContext – in charge for basic CRUD functionality
  • Unit Of Work combining the Repositories and orchestrating it by the process flow as needed.

 

image

 

Model Project – will be returned to client as part of an AJAX request

 

image

 

Web Project  –image

WebApi

  • routing issues connected to global.asax
  • Ninject IOC global configurations
  • bundle for js and css connectivity …and more

image

 

CSS/LESS

LESSLESS extends CSS with dynamic behavior such as variables, mixins , operations and functions.LESS runs on both the server-side (with Node.js and Rhino) or client-side (modern browsers only).

 

Opening the projects –

At the course he’s talking about building it from scratch there he’ll  open MVC4 template with WebApi template because we are going to serve WebApi services which will serve JSON for us,  but we already have the project from my previous post  – Getting Code Camper Started.

Now all we need is is to update the packages thought the NuGet Package Manager Console :

View –> Other Windows –> Package Manager Console

For instance write :

Update-Package jQuery   

It’ll uninstall the old version and install a new one.

After half an hour I’ve discovered the option of just –

Update-Package  which will update all of the packages in your project

 http://nuget.codeplex.com/wikipage?title=Updating%20All%20Packages

now I had all my packages updated at once .

 

I’ve resolved some bizarre issue with critical error on jQuery map and went on .

 

Helpful Tools

You can check out the series of the posts on the subject

<—SPA 1.1. Getting Code Camper Started

SPA 3– Data Models, Entity Framework, and Data Patterns –>

Tag Cloud

%d bloggers like this: