Download Web Atoms REST SDK from NuGet Package
https://www.nuget.org/packages/EntityRestSDK.NuGet

Entity REST SDK

Entity REST SDK is ASP.NET MVC Extension that allows you to build REST API quickly by defining simple rules to create DTO and Repository without having to create special classes for each.

Just Three Steps for REST API

  • Create Entity Framework Model (Database First)
  • Derive entities from AtomEntity
  • Create Security Context
  • Create a Controller class with Routing

Role of Security Context

SecurityContext class holds all necessary Linq Lambda Expressions that serves as firewall to your database. For every query or sub query, by default these rules will be applied first. So your data view will be always limited around your security rule.

Creating Controller that accesses a Model with predefined queries leads to too much code and maintenance nightmare. Creating a Repository with set of Security Rules automatically implied makes a huge difference for larger code base. Consider an example, I am a customer and when I am logged in I should only see my orders, and I can only modify certain fields of orders.

Problem with Repository pattern is, people often create multiple methods, for example, ListCustomerOrders, ListCustomerOrdersForProduct, ListCustomerOrdersForCategory etc. , such names increase over a period of time. Not only this, after certain point, same logic is replicated between different methods.

So Entity REST SDK is advanced version of automatic REST API, which lets you create simple security rules as lambda expressions and query them with easy JSON syntax.

  1. Atom Object Context
  2. Security Context
    1. Why Security Context?
    2. All CRUD with one Security Rule?
  3. Entity Controllers
    1. Web Atoms Controller
    2. Atom Entity Controller
  4. Dynamic Entity Controller
    1. Setting up Route
    2. Query (Returns List)
    3. Get
    4. Save
      1. Form Model
    5. Delete



 

AtomObjectContext

You must derive your ObjectContext class from AtomObjectContext instead of ObjectContext. Please note, this is not supported on DbContext, however AtomObjectContext wraps all useful functionality that came out in DbContext. Each entity must be derived from AtomEntity class which implements lCustomTypeProvider which adds serialization control attributes.


 

Security Context

Entity REST SDK relies on BaseSecurityContext class stores Security Rules in the form of simple lambda
expressions. These lambda expressions are security rules which are applied to entity framework.


 

Why Security Context?

SecurityContext is basically a rules section for accessing entire database. Usually creating different areas or different controllers based on different security roles leads to lots of Business Logic Duplication. With SecurityContext, your business logic can still remain same for all the roles, but your security rules will block the execution based on simple lambda expressions.

Changing Security Context is easier then changing business logic when new fields are added/removed and new roles are added.

Since SecurityContext just stores lambda expressions, its even easy to visualize and store/retrieve from other storage like XML or Database.

public class DefaultSecurityContext : BaseSecurityContext {

      public static DefaultSecurityContext Instance = new DefaultSecurityContext();

      // UserID for currently logged in User
      public static long UserID{
           get{
                 return long.Parse( HttpContext.Current.User.Identity.Name );
           }
      }

      public DefaultSecurityContext(){
      }
 
      protected override void OnCreate(){

            // User can access his own Account only
            var acc = CreateRules<Account>();

            acc.SetRead( y => x=> x.AccountID == UserID ) ;
            acc.SetWrite( y => x=> x.AccountID == UserID );

            // User can only modify AccountName and EmailAddress fields
            acc.SetProperties( SecurityRules.ReadWrite, 
                  x => x.AccountName,
                  x => x.EmailAddress);

            // User can read AccountType field
            acc.SetProperties<Account>( SecurityRules.Read, 
                  x => x.AccountType);

            // User can access his own Orders only
            var order = CreateRules<Order>();
            order.SetRead( y => x => x.CustomerID == UserID );
       
            // User can modify Order only if OrderStatus is not complete
            order.SetWrite( y => x => x.CustomerID == UserID && x.OrderStatus != "Complete" );

            // User can only modify OrderNotes and OrderStatus
            order.SetProperties( SecurityRules.ReadWrite, 
                  x => x.OrderNotes,
                  x => x.OrderStatus );

            // User can not delete orders
            order.SetDelete(order.NotSupportedRule);
      }
}


 

This way you can customize the rule in lot simpler way. Basically you have to return a delegate which in turn will be called upon the entity for any modify operation.



 

Does Security Rule work for all CRUD operations?

Yes, AtomObjectContext iterates every modified entity and verifies the Lamba Expressions against each entity to make sure they comply with rules. For example if in current security context, you were supposed to access/modify entities owned by you with CustomerID, then x => x.CustomerID == UserID should be true at all times, while search and modify. If this is not true, EntityException will be raised.


 

Entity Controllers

Entity Rest SDK comes with Two classes, one for implementing your own business logic which just wraps the security around object context and other is dynamic controller which supports full range of CRUD methods.


 

WebAtomsController<MyEntities>

This is a class that wraps SecurityContext functionality for normal MVC Controller, where all your custom CRUD operations are still secured against SecurityContext.

public class OrdersController : WebAtomsController <MyEntities> {
        protected override BaseSecurityContext CreateSecurityContext(){
             return DefaultSecurityContext.Instance;
        }

        public ActionResult SearchOrders( 
               string productName, 
               string orderBy = "OrderID DESC", 
               int start = 0, 
               int size = 10)
        {
               // Where method automatically applies
               // filter based on current SecurityContext

               var aq = Where<Order>();
               if(!string.IsNullOrEmpty(productName)){
                      aq = aq.Where( 
                                  x=> x.OrderItems.Any( 
                                     y=> y.Product.ProductName.StartsWith(productName)));
               }
                
               // OrderBy accepts string as a parameter
               aq = aq.OrderBy(orderBy);
               return aq.Page(start,size).Select( 
                     y=> new {
                            y.OrderID,
                            y.OrderDate,
                            y.OrderStatus,
                     });
        }
}


 

AtomEntityController<MyEntities> (Dynamic Entity Controller)

AtomEntityController is a dynamic entity controller, it automatically wraps all CRUD operations as mentioned in next section.


 

Dynamic Entity Controller

Dynamic Entity Controller serves as Dynamic Repository and creates Dynamic DTO based on Security Rules defined and query requested.


public class EntityController : 
     NeuroSpeech.WebAtoms.Mvc.AtomEntityController<MyBusinessEntities>
{

     // This will enforce all calls through security context
     protected override BaseSecurityContext CreateSecurityContext(){
           // Avoid creating new instance of SecurityContext, use a static instance
           // You can return different instances based on user type or role
           return DefaultSecurityContext.Instance;
     }
}


 

Setting up Route

Following code will map /app/entity/* route to AtomEntityController.
            context.MapRoute(
                "App_entity",
                "App/Entity/{table}/{action}",
                new { controller = "Entity", action = "Query" },
                new string[] { "MyApp.Areas.App.Controllers" }
            );

Dynamic Entity Controller already has generic methods that serve CRUD requests. They are called as follow,


 

Query (Returns List)

/app/entity/account/query?query={AccountID:2}&orderBy=AccountName&fields={AccountID:'',AcccountName:''}

query JSON Formatted JSON Query Language
orderBy SORT Field and Direction
fields JSON Formatted JSON Field Language
start Start record index for paging
size Size of Paging records



 

Get (Returns Single Object or null)

/app/entity/account/get?query={AccountID:2}&orderBy=AccountName&fields={AccountID:'',AcccountName:''}

query JSON Formatted JSON Query Language
orderBy SORT Field and Direction
fields JSON Formatted JSON Field Language
start Start record index for paging
size Size of Paging records



 

Save

/app/entity/account/save
POST: formModel={ 'AccountID':2, 'AccountName':'Akash Kava' }

JSON formatted object that represents primary key and fields values to update. This method will automatically check if record exists in database or not, if it does then it updates fields or it will insert new record.

In order for Save Method to work correctly, you must make sure that you pass a formModel as a form key and value as json expression. If you are using jQuery, then following will be correct example.

var data = { formModel: JSON.stringify(acc) };

$.ajax( '/app/entity/account/save', { data: data });

We have chosen this form of posting data as it is compatible with file upload. You can send files as well in above example. If you send data as JSON with json content type, then file upload will not work as expected. So we have reserved "formModel" as a reserved name for form items.

If you look at source code of WebAtomsController, you can easily customize name of the field and also use Json Content Type to read form data.


 

Delete

/app/entity/account/delete
POST: formModel={'AccountID':2}

To delete object, you need to send only Primary Key and its value in JSON Formatted object.

Intercepting Modify Methods

As dynamic controller automatically manages Insert, Update and Delete methods, however you can still create following public methods to intercept the execution. <Entity> represents name of class. Dynamic Controller automatically detects presence of method signature and if not found, it executes default execution routine and saves entities.

OnInserting(<Entity> e)

This method is invoked after object has been added to Object Context and before Save Changes method is called.

OnInserted(<Entity> e)

This method is invoked after Save Changes was called for entity that was to be inserted.

OnSaving(<Entity> e, ObjectStateEntry entry)

If entity already exists in database, then this method is invoked before Save Changes. Note that in this method, you can access ObjectStateEntry corresponding to the entity.

OnSaved(<Entity> e)

This method is invoked after Save Changes method was called.

OnDeleting(<Entity> e)

This method is invoked before Save Changes method is called for entity to be deleted from database.

OnDeleted(<Entity> e)

This method is invoked after Save Changes method was called.
 

Last edited Feb 20 at 10:09 AM by neurospeech, version 28