Posted in: ASP.NET

Fix issue with ASP.NET MVC Razor page intellisense

Posted on July 2, 2015 by Michael Roma

There is an issue that causes ASP.NET MVC Razor pages to stop syntax highlighting and intellisense to not work.

Add the following key to the web.config appSettings node:

<add key="webpages:Version" value="2.0.0.0" />

Umbraco 7 Code-First Dictionary Key Manager

Posted on June 19, 2015 by Michael Roma

This post shows a simple code-first dictionary manager for Umbraco 7. Click here to download the source.

First define the attribute class and a helper to get the details of an attribute by key name

// define the dictionary key attributes
public class DictionaryKeyAttribute : Attribute
{
    // define fields
    public string Name { get; set; }
    public string DefaultText { get; set; }

    // constructor
    public DictionaryKeyAttribute(string name, string defaultText)
    {
        Name = name;
        DefaultText = defaultText;
    }
}   

// helper that gets the details
private static DictionaryKeyAttribute GetDetails(Keys key)
{
    return key.GetType()
        .GetField(key.ToString())
        .GetCustomAttributes(typeof(DictionaryKeyAttribute), false)
        .SingleOrDefault() as DictionaryKeyAttribute;            
}

Here is the function that initializes the keys by creating new Umbraco dictionary entries if the key does not already exist

// function that inits the dictionary and add new items if needed
public static void Init()
{
    // get the service
    var locationService = ApplicationContext.Current.Services.LocalizationService;

    // get all languages
    var langs = locationService.GetAllLanguages();

    // go through each key
    foreach(var key in Enum.GetValues(typeof(Keys)))
    {
        // get details, check if any
        var keyDetails = GetDetails((Keys)key);
        if (keyDetails != null)
        {
            string keyName = String.Concat(Prefix, keyDetails.Name);
            if (!locationService.DictionaryItemExists(keyName))
            {
                // init the new item
                var newItem = new DictionaryItem(keyName);
                newItem.Translations = langs
                    .Select(lang => new DictionaryTranslation(lang, keyDetails.DefaultText));                        

                // save
                locationService.Save(newItem);
            }
        }
    }

}

The following functions can be used to extract the dictionary text by key

// function that returns a dictionary string
public static string GetText(string key)
{
    // get the service
    var locationService = ApplicationContext.Current.Services.LocalizationService;

    // find the dictionary item
    var item = locationService.GetDictionaryItemByKey(String.Concat(Prefix, key));
    if (item != null && item.Translations != null)
    {
        // get the current language
        int languageId = GetCurrentLanguage();

        // get the translation
        var t = item.Translations.FirstOrDefault(x => x.Language.Id == languageId);
        if (t == null)
        {
            t = item.Translations.FirstOrDefault();
        }

        // check if a translation
        if (t != null)
        {
            // return
            return t.Value;
        }
    }

    // fallback to empty
    return "";
}

// function that gets the dictionary string
public static string GetText(Keys key)
{
    // get the dictionary key details
    var keyDetails = GetDetails((Keys)key);
    if( keyDetails != null)
    {
        return GetText(keyDetails.Name);
    }

    // fallback to empty
    return "";
}

Last, define your key prefix and keys

// define prefix
public const string Prefix = "roma";

// define dictionary items
public enum Keys
{            
    [DictionaryKey("PageTitle", "{0} | Michael Roma Development")] PageTitle,
    [DictionaryKey("CategoriesTitle", "Categories")] CategoriesTitle
}

Here is a helper to get the current page's language

// function that gets the current language
public static int GetCurrentLanguage()
{
    // get the current page
    var currentPage = new UmbracoHelper(UmbracoContext.Current)
        .TypedContent(UmbracoContext.Current.PageId.Value);

    // check if a page
    if (currentPage != null)
    {
        // get the home page
        var home = currentPage.AncestorOrSelf(1);
        if (home != null)
        {
            // get the domains for home
            var domains = umbraco.cms.businesslogic.web.Domain.GetDomainsById(home.Id);
            if (domains.Count() > 0)
            {
                return domains[0].Language.id;
            }
        }
    }

    // if here, no language
    return 0;
}

Umbraco CMS Content Query functions using Examine

Posted on June 16, 2015 by Michael Roma

This post discusses a ContentHelper class that can be used to query the Umbraco content tree. Click here to download the source

The following functions take a Umbraco path or an IPublishedContent object to search for content under that given path/content. It also takes a parameter for "Type" which can be used to select only certain Document Types. You can use String.Empty for the path to search all documents.

// function that queries for the given path and type
public static IEnumerable<IPublishedContent> Query(string path, string type, bool cache)
{
    // define query
    Func<IEnumerable<IPublishedContent>> f = delegate()
    {
        // get the helper
        var helper = new UmbracoHelper(UmbracoContext.Current);

        // get examine
        var examine = Examine.ExamineManager.Instance;

        // build the criteria
        var criteria = examine.CreateSearchCriteria();

        // check if a type
        if (!String.IsNullOrEmpty(type))
        {
            criteria.NodeTypeAlias(type);
        }

        // check if a path
        if (!String.IsNullOrEmpty(path))
        {
            criteria.Field("__Path", path.MultipleCharacterWildcard());
        }

        // get the results
        var results = examine.Search(criteria);

        // return the list
        if (results != null)
        {
            return helper.TypedContent(results.Select(x => x.Id)).Where(x => x != null).OrderBy(x => x.SortOrder);
        }

        // else, empty 
        return new List();
    };

    // else, return
    return f();            
}

// function that query for the path of the given item and type
public static IEnumerable<IPublishedContent> Query(IPublishedContent item, string type)
{
    return Query(item.Path, type);
}

The following is a helper that finds the closest parent with the given Document Type

// function that finds the closest parent for the given type and given document
public static IPublishedContent GetClosestParent(IPublishedContent item, string type)
{
    // loop while a document
    while (item != null)
    {
        // check if the correct type
        if (item.DocumentTypeAlias == type)
        {
            // return it
            return item;
        }

        // go up
        item = item.Parent;
    }

    // if here, nothing
    return null;
}

// function that finds the closest parent for the given type and current document
public static IPublishedContent GetClosestParent(string type)
{
    // get the current document, if exists
    if (UmbracoContext.Current != null && UmbracoContext.Current.PageId.HasValue)
    {
        return GetClosestParent(GetContentById(UmbracoContext.Current.PageId.Value), type);
    }

    // else, null
    return null;
}

Automatically push data from a Kentico form to SalesForce using a Web to Lead form

Posted on April 5, 2014 by Michael Roma

This post shows how to have data from a Kentico form builder pushed to SalesForce automatically using the Web-To-Lead functionality.

The two pieces of information you need from SalesForce is your OID and the Web-To-Lead post URL.

Below is the class to post to SalesForce from a BizFormItem. This class can be created in your App_Code folder. You want to make sure you set SalesForceOID and SalesForceWebToLeadURL to the correct values. Next set SalesForceWebToLeadForms to list each Kentico Form you want to push over.

You will also want to update the mapField(LeadModel, string) function to correctly map your Kentico Form field names to the corresponding SalesForce field. If you have any custom fields, you will need to generate the Web-To-Lead form html and find the custom field name used.

// add these includes
using CMS.CMSHelper;
using CMS.FormEngine;

namespace roma
{
    public class SalesForceService : IDisposable
    {
    	// define sales force settings - should be in web.config
    	public static string SalesForceOID  = "00Di0000000AAAA";
    	public static string SalesForceWebToLeadURL = "https://www.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8";

    	// define forms we should integrate
    	public static string[] SalesForceWebToLeadForms = { "BizForm.ContactForm", "BizForm.SignUpForm" }

        // function that posts from the given form record
        public void PostLeadFromForm(BizFormItem formObject)
        {
            // get the form name that represents the list
            var form = 
                BizFormInfoProvider.GetBizFormInfo(
                    formObject.BizFormClassName.ToLower().Replace("bizform.", ""),
                    CMSContext.CurrentSiteID);
            string formName = form.FormDisplayName;
            
            // check if a web to lead
            if (SalesForceWebToLeadForms.Contains(formObject.BizFormClassName))
            {
                // create the model
                var model = new LeadModel();

                // map the fields
                foreach (var col in formObject.ColumnNames)
                {
                    mapField(model, formObject, col);
                }

                // post to sales force
                PostWebToLead(model);
            }
        }

        // function that maps the col to the correct model field
        private void mapField(LeadModel model, BizFormItem formObject, string col)
        {
        	// check the name
            switch (col.ToLower())
            {
                // email
                case "email":
                    model.Email = formObject.GetStringValue(col, "");
                    break;

                // company
                case "company":
                    model.Company = formObject.GetStringValue(col, "");
                    break;

                // first name
                case "fname":
                    model.FirstName = formObject.GetStringValue(col, "");
                    break;

                // last name
                case "lname":
                    model.LastName = formObject.GetStringValue(col, "");
                    break;

                // title
                case "title":
                    model.Title = formObject.GetStringValue(col, "");
                    break;

                // phone
                case "phone":
                    model.Phone = formObject.GetStringValue(col, "");
                    break;

                // last name
                case "city":
                    model.City = formObject.GetStringValue(col, "");
                    break;

                // last name
                case "state":
                    model.State = formObject.GetStringValue(col, "");
                    break;

                // message
                case "comments":
                    model.Message = formObject.GetStringValue(col, "");
                    break;
            }
        }

        // function that sends the given data to sales fource
        public void PostWebToLead(LeadModel model)
        {
            // build the request
            var request = WebRequest.Create(Config.SalesForceWebToLeadURL);
            request.Method = "POST";

            // build the post data
            var sb = new StringBuilder()            
                .AppendFormat("oid={0}", Config.SalesForceOID)
                .AppendFormat("&{0}={1}", "company", model.Company)
                .AppendFormat("&{0}={1}", "first_name", model.FirstName)
                .AppendFormat("&{0}={1}", "last_name", model.LastName)
                .AppendFormat("&{0}={1}", "email", model.Email)
                .AppendFormat("&{0}={1}", "title", model.Title)
                .AppendFormat("&{0}={1}", "city", model.City)
                .AppendFormat("&{0}={1}", "state", model.State)
                .AppendFormat("&{0}={1}", "phone", model.Phone)
                .AppendFormat("&{0}={1}", "description", model.Description)
                .AppendFormat("&{0}={1}", "lead_source", model.LeadSource)
                ;
            
            // convert post data to byte[]
            byte[] byteArray = Encoding.UTF8.GetBytes(sb.ToString());
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = byteArray.Length;

            // write to request
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();

            // get a response, read into string
            WebResponse response = request.GetResponse();
            dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            string responseFromServer = reader.ReadToEnd();            

            // clean up
            reader.Close();
            dataStream.Close();
            response.Close();
        }



        // dispose
        public void Dispose() { }

        // define model
        public class LeadModel
        {
            // define fields
            public string Company { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string Email { get; set; }
            public string Title { get; set; }
            public string City { get; set; }
            public string State { get; set; }
            public string Phone { get; set; }
            public string Message { get; set; }
            public string Description { get; set; }

            public string LeadSource
            {
                get { return "Web"; }
            }
        }
    }
}

Last, you need to add an event handler so we can pick up when a form has been submitted and push that data to SalesForce. Create a new class in your App_Code folder for the following class:

// add these includes
using CMS.FormEngine;
using CMS.SettingsProvider;

[CustomDocumentEvents]
public partial class CMSModuleLoader
{
	// define class for events
    private class CustomDocumentEventsAttribute : CMSLoaderAttribute
    {
    	// init - add events
        public override void Init()
        {
            // set event handlers
            ObjectEvents.Insert.After += Insert_After;
        }

        // event handler for after insert for an object
        void Insert_After(object sender, ObjectEventArgs e)
        {
            // check if a form record added
            if (e.Object is BizFormItem)
            {
                // push to sales force
                using( var s = new roma.SalesForceService())
                {
                    s.PostLeadFromForm((BizFormItem)e.Object);
                }
            }
        }
    }
}

 

ASP.NET C# Web.Config helper class

Posted on April 5, 2014 by Michael Roma

The following is a C# helper class that reads App Settings in your ASP.NET Web.config file.

// add this include
using System.Configuration;

namespace roma
{
    public static class Config
    {
        // example setting
        // numeric example   
        public static double CacheMinutes { get { return Get("roma.CacheMinutes"); } }
        
        // boolean example
        public static bool IsTestMode { get { return Get("roma.IsTestMode"); } }
        
        // email addresses
        public static string DefaultEmailTo { get { return Get("roma.DefaultEmailTo"); } }
        
        // constant contact
        public static string ConstantContactAPIKey { get { return Get("roma.ConstantContact.APIKey"); } }
        public static string ConstantContactAccessToken { get { return Get("roma.ConstantContact.AccessToken"); } }
        public static string ConstantContactEmailList { get { return Get("roma.ConstantContact.EmailList"); } }

        // sales force
        public static string SalesForceOID { get { return Get("roma.SalesForce.OID"); } }
        public static string SalesForceWebToLeadURL { get { return Get("roma.SalesForce.WebToLeadURL"); } }        


        // helper to extract a web config value
        private static T Get(string key)
        {
            // try to convert
            try
            {
                return (T)Convert.ChangeType(ConfigurationManager.AppSettings[key], typeof(T));
            }
            catch (Exception) { }

            // return default
            return default(T);
        }
    }
}