Considerations and Best Practices for Custom Controls
Important information to consider when creating and using custom controls with SmartForms.
When using a custom control with a custom handler on an anonymous form, the handler call is redirect to a login page if the full path to the handler is not included in the call. Confirm this issue by examining the web dev/debug tooling, looking for a 302 redirect on the handler call. To prevent this issue, prepend the handler’s path in your custom control’s code. For example:
https://servername/Runtime/Runtime/[Form]/[Form name]/[Handler]
https://servername/Runtime/Runtime/[View]/[View name]/[Handler]
This code block demonstrates a method of prepending the path to the MyCompany.MyAjaxHandler.handler call:
Prepending the path to the MyCompany.MyAjaxHandler.handler call
$.getJSON(
"./" + $('head>title').text().trim() + "/MyCompany.MyAjaxHandler.handler",
...
For more information see the KB article, Known Issue: Custom control handler call returns 302 redirect with anonymous forms
A MIME type (Multipurpose Internet Mail Extensions) is a label describing a type of data. MIME types serve the same purpose on the Internet as file extensions do on your computer. A web server serves content with a particular MIME type (text/html, for example) and a browser recognizes it as an HTML document that it can show. Browsers also allow content sniffing to determine the MIME type of that content and render it correctly. If a byte-stream of data that is an image is sent to a browser, but the data doesn't have the MIME type set, the browser can use content sniffing and read the headers in the data to determine that it is an image and render it correctly.
MIME type checking is a security feature that makes sure that web content is of the correct type before it is processed.
The K2 platform enables strict MIME-type checking on design time and runtime sites by adding the X-Content-Type-Options response header with the value NoSniff. This disables content sniffing and causes the browser to block execution or rendering of content that is of a different MIME type than what the site response is set to. For example, if the server response content-type is set to application/javascript, but a custom control has a request to load content that is set to text/plain, then that content is blocked and the custom control does not work as designed.
It is important to verify that your custom controls set the correct content type for requests that load content. When coding your custom control, the type you set in your content header must match the actual type of that content.
For more information on MIME type detection and security, see the following MSDN articles:
See the section on MIME type error in the Troubleshooting topic.
Internet Explorer does not show an image if the extension of the image is not the same as the actual content of the image. For example, if the image is a JPEG/JPG but the file extension is set to PNG, the image is blocked.
Caching data is a key method for optimizing performance, but you should be aware that this may cause some issues. These include views and forms not loading and rendering correctly, and your code changes not being executed because the data is cached. As an example, you're querying a SmartObject but the data in the SmartObject is cached and not updating. In this case you won't get the updated version of the content in your custom control until you clear the cache.
See the Cache Issues troubleshooting topic for more information.
- The control invokes the CreateChildControls() method before RenderContents() in cases where a child control is created.
- Custom controls by default are rendered within a Span Tag <span></span>. You may use a constructor to set this to another HTML tag type.
When building custom controls that process XML, it is best to use the XmlHelper methods of the SourceCode.Forms.Utilities API's for improved security.
The following is an example of one of the available methods:
XMLHelper example
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
// SourceCode namespaces used in the control
using SourceCode.Forms.Utilities;
namespace SmartForms.CustomControls
{
class ConsiderationsandBestPractices_XMLHelper_ServerSide
{
publicvoid Main(string xml, XmlDocument document)
{
StringBuilder builder = new StringBuilder();
XmlReader xmlreader;
XmlWriter xmlwriter;
// When building Custom controls that process XML it is best to use the XmlHelper methods
// of the SourceCode.Forms.Utilities API's for improved security.
document = XmlHelper.CreateXmlDocument(xml); //returns a XmlDocument
xmlreader = XmlHelper.CreateXmlReader(xml); //returns a XmlReader
xmlwriter = XmlHelper.CreateXmlWriter(builder); //returns a XmlWriter
XmlHelper.LoadXmlDocument(document, xml);
}
}
}
When building a custom control that directly handles SmartObject execution, it is best to obfuscate the SmartObject method name for improved security.
To do this, use the EncryptSmartObjectMethodName and DecryptSmartObjectMethodName methods of the ControlHelper class in the SourceCode.Forms.Controls.Web.SDK assembly.
An example of encryption
// SourceCode namespaces used in the control
using SourceCode.Forms.Controls.Web.SDK.Utilities;
namespace SmartForms.CustomControls
{
class ConsiderationsandBestPractices
{
// When building a Custom control that handles SmartObject execution directly it is best to obfuscate
// the SmartObject method name being executed for improved security. To do this developers should use
// the EncryptSmartObjectMethodName and DecryptSmartObjectMethodName methods of the ControlHelper class
// in the SourceCode.Forms.Controls.Web.SDK assembly.
// When building up the response - Encrypt
publicvoid Encrypt(string AssociationMethod, string AssociationSO)
{
if (ControlHelper.ObfuscateMethodNames) //Check if Obfuscation is enabled
{
AssociationMethod = ControlHelper.EncryptSmartObjectMethodName(AssociationMethod, AssociationSO);
}
}
}
}
An example of decryption
// SourceCode namespaces used in the control
using SourceCode.Forms.Controls.Web.SDK;
using SourceCode.Forms.Controls.Web.SDK.Attributes;
using SourceCode.Forms.Controls.Web.SDK.Utilities;
namespace CustomControl
{
//Link to the definition file
[ControlTypeDefinition("CustomControl.Definition.xml")]
class BasicControl : BaseControl
{
// When building a Custom control that handles SmartObject execution directly it is best to obfuscate
// the SmartObject method name being executed for improved security. To do this developers should use
// the EncryptSmartObjectMethodName and DecryptSmartObjectMethodName methods of the ControlHelper class
// in the SourceCode.Forms.Controls.Web.SDK assembly.
// When building up the response - Decrypt
publicvoid Decrypt(HttpContext context)
{
request.AssociationSO = context.Request.Form["SmartObjectGuid"];
request.AssociationMethod = context.Request.Form["SmartObjectMethod"];
if (ControlHelper.ObfuscateMethodNames) //Checks if obfuscation is enabled
{
request.AssociationMethod = ControlHelper.DecryptSmartObjectMethodName(request.AssociationMethod, request.AssociationSO);
}
}
// Supporting code below is used so this project will compile.
protectedoverridevoid RenderContents(System.Web.UI.HtmlTextWriter writer)
{
writer.Write(" <b>Basic Control</b>");
}
// Local class used to capture specific information from the Request object.
internalclass request
{
internalstaticstring AssociationMethod;
internalstaticstring AssociationSO;
}
}
}