Wednesday, February 22, 2017

Best Practices


01) use jquary class for module wise

example :-
                             
                      module Ecart.User.ViewInfo{
                             var m =  (()=>{
                                 var apiCalls ={
                                        get(e):{
                                             return $.ajax({});
                                        },
                                       insert(e):{
                                         return $.ajax({});
                                      }
                                },
                                function get(e?){
                                    if(!validateForm()){return;}
                                    apiCalls.get(e).done((r)=>{console.log(r);}).fail((r)=>{alert('failed');});
                                }
                               function insert(e?){
                                   if(!validateForm()){return;}
                                   apiCalls.insert(e).done((r)=>{console.log(r);}).fail((r)=>{alert('fail');});
                               }

                             function validateForm(){
                                    return true;
                             }
                                  return{
                                        int:()=>{
                                             // int controlls for this module.
                                            // call crud functions.
                                             $('#btnClick').on('click',this,insert);
                                        },
                                       
                                 }
                            });

                       $(document).ready(m.init);
                 }

02) Think Web api method as Noun. not as the verb.

      public class StudentController:ApiController{
           
          [HttpGet]
          [Route("Students")]
          public IHttpResponse Get(){}

          [HttpGet]
          [Route("Students/{id}")]
          public IHttpResponse Get(int id){}

          [HttpPost]
          [Route("Student}s")]
          public IHttpResponse Post(Student obj){}

          [HttpDelete]
          [Route("Students/{id}")]
          public IHttpResponse Post(int id){}

          [HttpPut]
          [Route("Students")]
          public IHttpResponse Put(Student object){}
  
     }
        
in that case use plural except singular for identity routing 

03) User Automapper to Domain transfer to Different Domain.


using X.App_Start
public class AutomapperConfig(){
     public void Register(){
       // register mapping
    }
}

// call to mapping from Globle.ascx
public class Globle{
  
     public void Application_Start(){
       // call to registration
       new AutomapperConfig().Register();
    }
}


04) Always return IHttpResponse type from Api method

          public IHttpResult Get(){
              try{
                   if(!Validate()){
                       return BadRequest('error list converted to json');
                    }
                    else{ 
                       return Ok<T>(result); 
                     }
                    }catch(Exception e){
                return Content<Exception>(HttpStatusCode.InternalServerError,e);
              }
         }

05) Be Always Asyncronas 

          public async Task <IHttpResult> Insert(T object){
                 await c.Insert(T); 
                 return Ok();
         }


06) Always do Server side validation.


     public static bool IsModelValied(object x, out List<string> e)
        {
            ValidationContext context = new ValidationContext(x, null, null);
            IList<ValidationResult> errors = new List<ValidationResult>();
            var ex = new List<string>();
            bool isValied = true;
            if (!Validator.TryValidateObject(x, context, errors, true))
            {
                isValied = false;
                foreach (ValidationResult result in errors)
                {
                    ex.Add(result.ErrorMessage);
                }
            }
            e = ex;
            return isValied;
        }
              

   public Task<IHttpResponse> Insert(T obj){

         var err = new List<string>();
          if(!IsModelValied(T,out err)){
             return BadRequest(JSON.Stringify(err));
           }
         return Ok();
    }

07) Use Dependency injection 

Controller 

public class StudentService:ApiController{

      StudentDbService service;
      public A(UnitOfWork _uow){
          serice = new StudentDbServive(_uow);
      }

}

08) Use Lamda Expression what you need

public void Insert(){

     var lst = new List<T>();
     Action<string> come = (e)=>{ lst.Add(e); };

     Predicate<string> =passwordLength= (e)=>{ return e.length > 10; }
    
     Func<string,string>  some2 = (e) =>{ return e.string();}
}


09) use Unit of work.


public interface IUnitOfWork
   {
       GenericRepository<Student> StudentRepository { get; }
       GenericRepository<Subject> SubjectRepository { get; }
       GenericRepository<StudentSubject> StudentSubjectRepository { get; }
       GenericRepository<UserAuthontication> UserAuthonticationRepository { get; }
       void Save();
       Task SaveAsync();
       DbContext Context { get; }
 
   }
   public class UnitOfWork : IUnitOfWork, IDisposable
   {
       public UnitOfWork(IContext cnt, Enums.ERunType type)
       {
           if (type == Enums.ERunType.Debug)
           {
               context = (SchoolContext)cnt;
               context.Configuration.AutoDetectChangesEnabled=false;
           }
           else
           {
               context = (MockDbContext)cnt;
           }
       }
       private DbContext context;
       private GenericRepository<Student> studentRepository;
       public DbContext Context
       {
           get
           {
               return context;
           }
       }
       public GenericRepository<Student> StudentRepository
       {
           get
           {
 
               if (this.studentRepository == null)
               {
                   this.studentRepository = new GenericRepository<Student>(context);
               }
               return studentRepository;
           }
       }
public void Save()
        {
            context.SaveChanges();
        }
        public async Task SaveAsync()
        {
            await context.SaveChangesAsync();
        }
        private bool disposed = false;
 
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposed = true;
        }
 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }


10) Use Genaric repository


public class GenericRepository<TEntity> where TEntity : class
  {
      internal DbContext context;
      internal DbSet<TEntity> dbSet;
 
      public GenericRepository(DbContext context)
      {
          this.context = context;
          this.dbSet = context.Set<TEntity>();
      }
 
      public virtual IEnumerable<TEntity> Get(
          Expression<Func<TEntity, bool>> filter = null,
          Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
          string includeProperties = "")
      {
          IQueryable<TEntity> query = dbSet;
 
          if (filter != null)
          {
              query = query.Where(filter);
          }
 
          foreach (var includeProperty in includeProperties.Split
              (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
          {
              query = query.Include(includeProperty);
          }
 
          if (orderBy != null)
          {
              return orderBy(query).ToList();
          }
          else
          {
              return query.ToList();
          }
      }
 
      public virtual TEntity GetByID(object id)
      {
          return dbSet.Find(id);
      }
 
      public virtual void Insert(TEntity entity)
      {
          dbSet.Add(entity);
      }
 
      public virtual void Delete(object id)
      {
          TEntity entityToDelete = dbSet.Find(id);
          if (entityToDelete!= null)
          {
              Delete(entityToDelete);
          }
      }
 
      public virtual void Delete(TEntity entityToDelete)
      {
          if (context.Entry(entityToDelete).State == EntityState.Detached)
          {
              dbSet.Attach(entityToDelete);
          }
          dbSet.Remove(entityToDelete);
      }
 
      public virtual void Update(TEntity entityToUpdate)
      {
          dbSet.AddOrUpdate(entityToUpdate);
      }
  }


11. Be Interface Every ware

Api base interface

public interface IService<T>  
   {
       Task<IHttpActionResult> Insert(T item);
       Task<IHttpActionResult> Delete(int Id);
       Task<IHttpActionResult> Update(T item);
       Task<IHttpActionResult> Get();
       Task<IHttpActionResult> GetSingle(int studentId);
   }
public class StudentServiceController : BaseServiceController, IService<StudentViewModel>
  {

PlutoContext

   public interface IContext
    {
        DbSet<Student> Students { get; set; }
        DbSet<Subject> Subjects { get; set; }
        DbSet<StudentSubject> StudentSubjects { get; set; }
        DbSet<UserAuthontication> UserAuthontications { get; set; }
    }
 
   public class SchoolContext : DbContext,IContext 
   {


Genatic repository

public interface IRepositoryRead<T> where T : class
   {
       IEnumerable<T> Get(Expression<Func<T, bool>> filter = null,
           Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
           string includeProperties = "");
       T GetByID(object id);
   }
 
   public interface IRepositoryUpdate<T> where T : class {
       void Insert(T entity);
       void Delete(object id);
       void Delete(T entityToDelete);
       void Update(T entityToUpdate);
   }
 
   public interface IRepositoryUpdateAsync<T> where T : class {
 
       Task<int> InsertAsync(T entity);
       Task DeleteAsync(object id);
       Task UpdateAsync(T entityToUpdate);
   }

public interface IStudentDbService : IRepositoryRead<StudentBo>, IRepositoryUpdateAsync<StudentBo>
    {
        IEnumerable<StudentBo> Get(Expression<Func<Student, bool>> filter = null, Func<IQueryable<Student>, IOrderedQueryable<Student>> orderBy = null, string includeProperties = "");
    }

public class StudentDbService : IStudentDbService
   {
.............................


12) Use cache everywhere


using System.Runtime.Caching;
public class MemoryCacher
    {
        public static bool Add(string key, object value, DateTimeOffset absExpiration)
        {
            MemoryCache memoryCache = MemoryCache.Default;
            return memoryCache.Add(key, value, absExpiration);
        }
 
        public static object GetValue(string key)
        {
            MemoryCache memoryCache = MemoryCache.Default;
            return memoryCache.Get(key);
        }
         
        public static void Delete(string key)
        {
            MemoryCache memoryCache = MemoryCache.Default;
            if (memoryCache.Contains(key))
            {
                memoryCache.Remove(key);
            }
        }
    }

in this case put all cache keys in one place like CacheKeysConfig.cs as const string.

13). Use Json Format


config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html"));

14) Use Following Folder structure



     X (Api,Utility/)
     Lib /
          X.Domain
          X.Bo -->Utility(Enums)
          X.DbAccess --> Context / Migration
          X.DbService --> Service / Interface / Infastucture
     Test / X.UnitTest,X.AutomationTest,X.MockData


15) use attribute base routing for.

01) api versioning.
02) web api method as noun

[RouterPrefix('v1')]
public class StudentController:ApiController{

[Route("student")]
       public async Task<IHttpActionResult> Get()
       {}
[Route("student/{Id:int}")]
       public async Task<IHttpActionResult> GetSingle(int Id)
       {}
[Route("student")]
        public async Task<IHttpActionResult> Insert(StudentViewModel item)
        {}

[Route("student")]
        public async Task<IHttpActionResult>  Update(StudentViewModel item)
        {}

[Route("student/{Id:int}")]
       public async Task<IHttpActionResult> Delete(int Id)
       {}
}

     

16) use observer to bind values to html.


17) use template for itoration date


18) Use GZip To compress result

https://damienbod.com/2014/07/16/web-api-using-gzip-compression/
https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression
   


19) KISS (Keep It Simple and Stupid)


  1. do not expose more than expert.
  2. return thing in similar way.
    public async Task<IHttpResponse> Response(){
         return Ok<T>(value);
         return BadRequest(string content);
         return Component(ResponseCode.InternalServerError,Ex);
    }
  3. use only common Response Code. not all. 404/200/401/500/403

20) Documentation 


21) Consider about Versioning

       [RouterPrefix('api/v2')]
       public class StudentController : ApiController{}



22) Result Filtering / Sorting / Searching / Pagination



    quay string  GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at&skip=10&take=100




23) Errors and Exception Handling


return json message format 
{ "code" : 1024, "message" : "Validation Failed", "errors" : [ { "code" : 5432, "field" : "first_name", "message" : "First name cannot have fancy characters" }, { "code" : 5622, "field" : "password", "message" : "Password cannot be blank" } ] }





24) use Customer action filter always

public XController:ApiController{ [Validation] public async Task<IHttpResponse> Insert(Student s){ return null; } } public ValidationActionFilter:ActionFilter{ public override void OnActionExecuting(HttpContext x){ //check context model state is valied if(!x.ModelState.IsValied()){ //set context as bad request x.Response = new HttpResponseMessage<Json>("some validation failded",badRequest); } } } // finally this action filter must register on Globle.asax public static void Configure(config){ config.Filter.Add(new ValidationActionFilter()); }

25) User Following exception type for following reasons.

406 - notAcceptable (not trigger on database (primary key violation))
404 - not found
200 - OK
201 - created
403 - Forbidden
400 - bad request

26 Handle sql exception (Primary key | forign key) by following way

custom exception for db
public class DbPKViolationException:Exception
    {
        public DbPKViolationException() : base() { }
        public DbPKViolationException(string message) : base(message) { }
    }
    public class DbFKViolationException : Exception
    {
        public DbFKViolationException() : base() { }
        public DbFKViolationException(string message) : base(message) { }
    }
    public class DbUniqKeyViolationException : Exception
    {
        public DbUniqKeyViolationException() : base() { }
        public DbUniqKeyViolationException(string message) : base(message) { }
    }

genetic exception handler

protected Exception HandleException(Exception exception)
       {
           var x = exception;
           while (x.InnerException != null)
           {
               x = exception.InnerException;
           }
           var sqlException = x as SqlException;
           if (sqlException==null)
           {
               throw x;
           }
           if (sqlException.Number == 2627 || sqlException.Number == 2601)
           {
               throw new DbPKViolationException();
           } 
           throw exception;
       }
   }


Service class : base service


public UserBo GetByID(object id)
       {
           try
           {
               return Mapper.Map<UserBo>(this.uow.UserRepository.GetByID(Convert.ToUInt32(id)));
           }
           catch (Exception ex)
           {
               throw HandleException(ex);
           }
       }


Controller class

[HttpPost]
[Route("user/login")]
public async Task<IHttpActionResult> Login(UserViewModel entity)
{
    try
    {
        var o = this.service.Login(Mapper.Map<UserBo>(entity));

        return Ok();
    }
    catch (ArgumentException)
    {
        return Content<string>(HttpStatusCode.NotAcceptable, "invalied user name or password");
    }
    catch (Exception ex)
    {
        return await LogErrors(ex);
    }
}




Wednesday, February 15, 2017

Lambda expression


Delegate



 delegate string AppendName (string firstName, string lastName);
public static void main(){

       AppendName nc = delegate (string firstName, string lastName)
            {
                var s = sequenceId.ToString();
                var zero = string.Empty;
                for (var i = 0; i < (5 - s.Length); i++)
                {
                    zero += "0";
                }
                var serialNumber = $"{eventId.Substring(10, 5)}-{zero}{sequenceId}";
                return serialNumber;
            };

     nc("chamith","saranga");
     nc("sajeeka","nanayakkara");
   nc("nalaka","gamage");
}


Func (return function)


public static void main(){


       Func<string,string> append = (e)=>{
   
          return e.toLower();

     };

   append("chamith");
}

 BookingItems = ((Func<List<BookingItemBo>>) (() =>
                    {
                        return result.BookingItem.Select(p => new BookingItemBo(p.ScheduleId, p.SeatNo,
                            p.BookingItemJourneyInfo.FromCityId, p.BookingItemJourneyInfo.ToCityId,
                            p.BookingItemJourneyInfo.FromStopId, p.BookingItemJourneyInfo.ToStopId,
                            p.BookingItemJourneyInfo.JourneyStartDateTime.SpecifiedAsUtc(),
                            p.BookingItemJourneyInfo.JourneyEndDateTime.SpecifiedAsUtc(),
                            p.Customer)).ToList();
                    }))()

Action (void function)


public static void main(){

      Action<string> print = (e) =>{

         console.WriteLine(e);
      };
}


Multiple parameter with Func


Func<int, int, int> getRate = (e,d) =>
                   {
 
                       return 1;
                   };

Pass function as a parameter using lamda expression

   static void Main(string[] args)
        {
            int result = 0;
            LamdaExpression(10,15,(e) => { result = e; });
            System.Console.WriteLine($"this is lamda expression {result}");
            System.Console.Read();
        }

        static void LamdaExpression(int first,int second,Action<int>  abc)
        {
            abc(first+second);
        }

-----------------------------------------------
public class Program
{
    static void Main(string[] args)
    {
        var x = new Process();
        x.LongRuniningProcess((int x2)=> {
            Console.WriteLine(x2);
        });
    }
}
public class Process
{
    public void LongRuniningProcess(Action<int> callBack)
    {
        for (int i = 0; i < 10000; i++)
        {
            Thread.Sleep(100);
            //copy file
            callBack(i);
        }
    }   

}

=======================================================
Enumerable (create list with some defaults)


  1. create List<int> from 0 to 100
    IEnumerable<int> arr = Enumerable.Range(0, 100);
  2. create List<T> with some default object.
    IEnumerable<Student> str = new Enumerable.Repeate(new Student("CHAMITH"),10);






Tuesday, January 31, 2017

Hosted Payment

Monaris

function PaymentMoneris(insertdata) {
        TsMessage.Show("Redirect to Moneris hosted payment", TsMessage.MessageType.Success);
 
        var url = "https://esqa.moneris.com/HPPDP/index.php"; // sand box
        if (settingsI.MonerisIsTestServer == false) {
            url = "https://www3.moneris.com/HPPDP/index.php"; // original
        }
 
        var postValues = {
            "ps_store_id": settingsI.MonerisID,
            "hpp_key": settingsI.MonerisKey,
            "charge_total": settingsI.TotalAmount.toFixed(2),
            "cust_id": "custcode:" + settingsI.Customers + "-id:" + settingsI.userid,
            "order_id": "oid" + insertdata.TransId,
            "lang": "en-ca",
            "email": settingsI.email,
            "bill_first_name": insertdata.FirstName,
            "bill_last_name": insertdata.LastName,
            "bill_address_one": insertdata.Address1,
            "bill_city": insertdata.City,
            "bill_state_or_province": insertdata.StateProvince,
            "bill_postal_code": insertdata.PostalCodeZIP,
            "bill_country": insertdata.Country,
            "bill_phone": insertdata.Phone,
            "rvar_mode": settingsI.CheckOutType
        };
 
        for (var i = 0; i < insertdata.InvoiceDetails.length; i++) {
            var breakoutdata = insertdata.InvoiceDetails[i];
            var quantity = 1;
            var pos = i + 1;
 
            postValues["id" + pos] = breakoutdata.EventCode;
            postValues["description" + pos] = breakoutdata.EventName;
            postValues["quantity" + pos] = quantity;
            postValues["price" + pos] = breakoutdata.EventAmount;
            postValues["subtotal" + pos] = breakoutdata.EventAmount * quantity;
        }
 
        PostRedirect.redirect(url,
            postValues,
            "POST");
    }
 
parameter description 

settingsI.MonerisID //public key
"ATNEQtore3"
settingsI.MonerisKey // private key
"hpFGG67Q5VJJ"
settingsI.TotalAmount.toFixed(2) // amount
"500.00"
"custcode:" + settingsI.Customers + "-id:" + settingsI.userid // customer id
"custcode:ADAMM002-id:123456789c"
 "oid" + insertdata.TransId // order id (when rederect the page this will pass from gate way to our site)
"oid1149"
settingsI.email
"admintestuser@townsuite.com"
settingsI.CheckOutType
1

payment interface

// sandbox configuration

If you do not have the moneris key and id login at https://esqa.moneris.com/mpg/index.php (Only store 3 supports interac).

Valid credit cards for testing

  • MasterCard 5454545454545454
  • Visa 4242424242424242
  • Amex 373599005095005
  • Diners 36462462742008

Valid debit cards for testing

INTERAC Online Select test bank
Valdid IDEBIT_TRACK2 values
  • 3728024906540591206=01121122334455000
  • 5268051119993326=01121122334455000000
  • 453781122255=011211223344550000000000

Configuration Url

Accept

http://localhost:52469/monerishostedreceipt

accept function C#

public void monerishostedreceipt{
try
           {
               Card = GlobalMethods.RequestParam("card");
 
               if (Card == "P")
               {
                   // interac online
                   IssName = GlobalMethods.RequestParam("ISSNAME");
                   Invoice = GlobalMethods.RequestParam("INVOICE");
                   IssConf = GlobalMethods.RequestParam("ISSCONF");
               }
               else
               {
                   IssName = "";
                   Invoice = "";
                   IssConf = "";
               }
 
               ResponseOrderId = GlobalMethods.RequestParam("response_order_id");
               DateStamp = GlobalMethods.RequestParam("date_stamp");
               TimeStamp = GlobalMethods.RequestParam("time_stamp");
               BankTransactionId = GlobalMethods.RequestParam("bank_transaction_id");
               ChargeTotal = decimal.Parse(GlobalMethods.RequestParam("charge_total"));
               BankApprovalCode = GlobalMethods.RequestParam("bank_approval_code");
               IsoCode = GlobalMethods.RequestParam("iso_code");
               Message = GlobalMethods.RequestParam("message");
               TransName = GlobalMethods.RequestParam("trans_name");
               CardHolder = GlobalMethods.RequestParam("cardholder");
               F4l4 = GlobalMethods.RequestParam("f4l4");
               CardUserFriendly = GetHumanReadableCardType(Card);
               ExpiryDate = GlobalMethods.RequestParam("expiry_date");
               Result = GlobalMethods.RequestParam("result");
               ResponseCode = GlobalMethods.RequestParam("response_code");
               Mode = GlobalMethods.RequestParam("rvar_mode");
 
               ProcessData();
           }
           catch (Exception ex)
           {
               TownSuiteWebPortals.Trace.TrapErrors(ex);
               TownSuiteWebPortals.Messages.Show(this, "An unknown error occurred.", Messages.MessageType.Error);
           }
}

Reject

http://localhost:65299/monerishosteddeclined

rejected function

public void monerishosteddeclined ()
       {
 
           try
           {
 
               Card = MonerisHostedReceipt.GetHumanReadableCardType(GlobalMethods.RequestParam("card"));
 
               if (Card == "P")
               {
                   // interac online
                   IssName = GlobalMethods.RequestParam("ISSNAME");
                   Invoice = GlobalMethods.RequestParam("INVOICE");
                   IssConf = GlobalMethods.RequestParam("ISSCONF");
               }
               else
               {
                   IssName = "";
                   Invoice = "";
                   IssConf = "";
               }
 
               ResponseOrderId = GlobalMethods.RequestParam("response_order_id");
               DateStamp = GlobalMethods.RequestParam("date_stamp");
               TimeStamp = GlobalMethods.RequestParam("time_stamp");
               BankTransactionId = GlobalMethods.RequestParam("bank_transaction_id");
 
               // On a cancel request this will be an empty string
               decimal cTotal = 0m;
               decimal.TryParse(GlobalMethods.RequestParam("charge_total"), out cTotal);
               ChargeTotal = cTotal;
 
               BankApprovalCode = GlobalMethods.RequestParam("bank_approval_code");
               IsoCode = GlobalMethods.RequestParam("iso_code");
               Message = GlobalMethods.RequestParam("message");
               TransName = GlobalMethods.RequestParam("trans_name");
               CardHolder = GlobalMethods.RequestParam("cardholder");
               F4l4 = GlobalMethods.RequestParam("f4l4");
               ExpiryDate = GlobalMethods.RequestParam("expiry_date");
               Result = GlobalMethods.RequestParam("result");
               ResponseCode = GlobalMethods.RequestParam("response_code");
 
               ProcessData();
           }
           catch (Exception ex)
           {
               TownSuiteWebPortals.Trace.TrapErrors(ex);
               TownSuiteWebPortals.Messages.Show(this, "An unknown error occurred.", Messages.MessageType.Error);
           }
       }

Configuration page
https://esqa.moneris.com/mpg/admin/hppv3_config/index.php







Sql server row level policy