Code Modules


Code modules usually are used as route handlers.

Examples bellow are created using Pims R4

Minimal example of code module

Response type will be text/html. Route will be available public.

    
    using Appframe.Web.Context;
    using Appframe.Web.Registries.Attributes;
    using Appframe.Web.RouteHandlers;

    namespace RouteHandlers
    {
        [RouteUrl("api/testing-module")]
        public class testing_class : ReusableRouteHandlerBase
        {
            protected override void Process(RequestContext pContext) {
                pContext.Response.Output.Write("Hello, I'm Appframe");
            }
        }
    }
    

Route parameters

To pass parameters via route you should define different path.

Note: Always try to parameterize user inputs. In this case we can use RouteParametersBase to create class for route parameters

    
    using System; // Adding System lib for String.format function. 
    [RouteUrl("api/testing-module/{some_string}/{some_int}")] 
    public class testing_class2 : ReusableRouteHandlerBase { 
        private class RouteParameters:RouteParametersBase{} 
        public string some_string { get; set; } 
        public int some_int { get; set; } 
        public RouteParameters(RequestContext pContext) : base(pContext) { } 
        protected override void Process(RequestContext pContext) { 
            var vParamaters = new RouteParameters(pContext); 
            pContext.Response.Output.Write(String.Format("Hello, I'm Appframe. You passed: {0} and {1}",vParamaters.some_string,vParamaters.some_int)); 
        } 
    }   
        
    

Post parameters

You might need to have more paramaters available. And from now on we will switch to JSON reponse type.

    
    string vJson1; 
    int vJson2; 
    if(pContext.JsonParameters.ContainsKey("json1")) vJson1 = pContext.JsonParameters["json1"].ToString(); 
    if(pContext.JsonParameters.ContainsKey("json2")) vJson2 = int.Parse(pContext.JsonParameters["json2"].ToString());
    

AfRecordSource

We should use afRecordSource and ConnectionContext.Current methods fro CRUD operations AddData, GetData, PutData, DelData

    
    private class RouteParameters:RouteParametersBase{ 
        public Guid PrimKey { get; set; } 
        public RouteParameters(RequestContext pContext) : base(pContext) { } 
    } 
    protected override void Process(RequestContext pContext) {
         /* We will accept only post requsts*/ 
         if (pContext.Request.HttpMethod != "POST") throw new HttpException(405, "Method not allowed"); /* using System.Web; for HttpException*/ 
         if (!pContext.IsAjaxRequest) throw new HttpException("Only Ajax requests are supported"); 
         var vParamaters = new RouteParameters(pContext); 
         var vRs = new afRecordSource("atbv_Testing_TestXss"); 
         vRs.MaxRecords = 1; 
         vRs.SelectColumns.AddRange(new String[]{"Tag","Content"}); 
         /* PrimKey is guid, so putting it in such maner is safe */ 
         vRs.WhereClause = "PrimKey = '"+vParamaters.PrimKey.ToString()+"'"; 
         /* Additionally if we would need master child */
         if(pContext.JsonParameters.ContainsKey("MasterChildCriteria")){ 
            var vMasterChildCriteria = (Newtonsoft.Json.Linq.JObject)pContext.JsonParameters["MasterChildCriteria"];
            foreach (var vCriteria in vMasterChildCriteria) {
                vRs.MasterChildCriteria.Add(vCriteria.Key, vCriteria.Value.ToString()); 
                }  
            //Filter string 
            if(pContext.JsonParameters.ContainsKey("FilterString")) vRs.FilterString = pContext.JsonParameters["FilterString"].ToString(); 
            var vDataTable = ConnectionContext.Current.GetData(vRs); JSON.SerializeToResponse(vDataTable, pContext); 
        }
    }
    

Executing procedure

    
    afProcedureCall vProc = new afProcedureCall("astp_NamSpace_Name"); 
    vProc.Parameters.Add("Param", pParam); 
    vProc.Parameters.Add("Pram", HTMLSanitizer.Sanitize(pParam)); //Values can be auto Sanitized if it is set in web.config 
    UserContext.RequireCurrent.ExecuteProcedure(vProc);//return DataSet if any value in return
    

Some other methods

    
    /* We will accept only post requsts */ 
    if (pContext.Request.HttpMethod != "POST") throw new HttpException(405, "Method not allowed"); /* using System.Web; for HttpException*/ 
    /*Check is it Ajax request*/ 
    if (!pContext.IsAjaxRequest) throw new HttpException("Only Ajax requests are supported"); 
    /* Set to inform browser not to cache response */ 
    pContext.Response.Cache.SetNoStore() 
    /* To allow only logged in user to perform tasks */ 
    if(!Context.UserContext.IsUserAuthenticated) throw new HttpException("You need to be logged in"); 
    /* To allow only developers to perform tasks */ 
    if(!UserContext.RequireCurrent.IsDeveloper) throw new HttpException("You need to be developer"); 
    /* Use DeveloperRouteHandlerBase instead of ReusableRouteHandlerBase if you need auto handle check from 2 factor authentication and if user is developer :*/
     public class developer_class : DeveloperRouteHandlerBase 
     /* To get article context */ 
     var vArticleContext = pContext.SiteAliasContext.GetArticle("ArticleID"); 
     /* To get recordsource */
     var vRs = vArticleContext.GetRecordSource("DataSourceID");

    

Usage statistics and tracking

In 365 you can enable route handler usage tracking to see if your codemodules are being used. To do that add LogRouteHandlers in to your web config app settings section as shown below

     
    

When this settings is enabled stbl_WebSiteCMS_Log will be filled with additional data.

  • Solution_ID - ID of a solution the log is comming from
  • UrlReferer - url that referenced url
  • RouteHandlerFullName - Fully qualified name of route handler
  • ModuleRef - module ref or primkey in code modules table
  • IsObsoleteHandler - determines route handle is using proper base class

Related articles