This information applies to Adxstudio Portals 5.0 and later.

While Adxstudio Portals uses ASP.NET Web Forms to in order to provide its CMS templating experience, it also includes support for ASP.NET MVC 4, allowing developers to extend their Adxtudio Portals application using that framework.

As Adxstudio Portals applications remain dependent on content-managed URLs for routing and ASP.NET Web Forms for templating, the Adxstudio Portals framework allows hybrid applications, where custom modules can be developed using MVC, while the rest of the application uses Web Forms.

Getting Started

To use ASP.NET MVC in your Adxstudio Portals application, you'll need to add references to the following MVC 4 framework assemblies. If these cannot be found on your system, you can install MVC 4 by following the instructions on the ASP.NET MVC 4 home page.

  • System.Web.Mvc (4.0)
  • System.Web.WebPages (2.0)

Next, you'll need to configure your application to route certain URL paths to your MVC controller(s).

Routing

In order to route URL paths to your MVC controllers, you can use the standard MVC routing APIs. However, Adxstudio Portals provides an additional API, in the form of the MapSiteMarkerRoute method.

MapSiteMarkerRoute works in similar fashion to the standard MapRoute API, except that it takes a Site Marker name as its second argument. What this does is maps the route to reside under the content-managed URL path represented by the given site marker. For example, in the code below, if the site marker "Ideas" is related to a Web Page with a Partial URL of "ideas" and the site Home page as its Parent Page, the actual route represented is /ideas/idea/{action}/{id}. This route will change dynamically if the URL of the Web Page is updated.

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Adxstudio.Xrm.Web.Mvc;

namespace Site
{
	public class Global : HttpApplication
	{
		public static void RegisterGlobalFilters(GlobalFilterCollection filters)
		{
			filters.Add(new PortalViewAttribute());
		}

		public static void RegisterRoutes(RouteCollection routes)
		{
			routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

			routes.MapRoute(
				"Account",
				"account-signout",
				new { controller = "Account", action = "SignOut" });

			routes.MapSiteMarkerRoute(
				"IdeaActions",
				"Ideas",
				"idea/{action}/{id}",
				new { controller = "Idea", action = "Index", id = Guid.Empty });
		}

		void Application_Start(object sender, EventArgs e)
		{
			RegisterGlobalFilters(GlobalFilters.Filters);
			RegisterRoutes(RouteTable.Routes);
		}
	}
}

Using MapSiteMarkerRoute instead of MapRoute has the following advantages:

  • It will be possible for content author users to manage the root URL path segment of your MVC route.
  • Within your MVC controller, the Adxstudio Portals framework will consider the current page context to be the Web Page referenced by your site marker. This means that Site Map-based navigation elements (breadcrumbs, etc.) will work as expected within your MVC views.

View Helpers

Adxstudio Portals provides a number of MVC view helpers, allowing you to access Adxstudio Portals data from your MVC views. These helpers are found in the Adxstudio.Xrm assembly, in the namespace Adxstudio.Xrm.Web.Mvc.Html, and provide access to Adxstudio Portals features such as Content Snippets, Site Settings, Site Markers, Web Links, and general front-side editable entity attributes. Additional documentation for individual helper methods can be found in the API documentation included with your Adxstudio Portals installation.

In order to use these helpers in your views, you must first add the Adxstudio.Xrm.Web.Mvc.PortalViewAttribute action filter attribute to your MVC controller. This action filter will set up necessary view context information required by these helpers.

This attribute can be added directly to a single controller, like so:

using System.Web.Mvc;
using Adxstudio.Xrm.Web.Mvc;

namespace Site.Controllers
{
	[PortalView]
	public class ExampleController : Controller
	{
	}
}

Or, this action filter can be added to all controllers in your application, in your application Global.asax, like so:

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Adxstudio.Xrm.Web.Mvc;

namespace Site
{
    public class Global : HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new PortalViewAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            
        }

        void Application_Start(object sender, EventArgs e)
        {
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

Once this attribute is present, you can use the Adxstudio Portals view helpers in your view, like so:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<%@ Import namespace="Adxstudio.Xrm.Web.Mvc.Html" %>
<!DOCTYPE html>
<html>
<head runat="server">
  <title>
    <%: Html.AttributeLiteral("adx_title") ?? Html.AttributeLiteral("adx_name") %>
    <%= Html.SnippetLiteral("Browser Title Suffix") %>
  </title>
  <link rel="stylesheet" href="<%: Url.Content("~/css/portal.css") %>">
</head>
<body>
  <header>
    <%: Html.HtmlSnippet("Header") %>
    <%: Html.WebLinks("Primary Navigation", false, false, "weblinks", "nav") %>
    <ul class="nav pull-right">
      <% if (Request.IsAuthenticated) { %>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown">
            <%: Html.AttributeLiteral(Html.PortalUser(), "fullname") %>
            <span class="caret"></span>
          </a>
          <ul class="dropdown-menu">
            <li>
              <a href="<%: Html.SiteMarkerUrl("Profile") %>">
                <%: Html.SnippetLiteral("Profile Link Text", "Profile") %>
              </a>
            </li>
            <li>
              <a href="<%: Url.Action("SignOut", "Account", new { returnUrl = Request.RawUrl }) %>">
                <%: Html.SnippetLiteral("links/logout", "Sign Out") %>
              </a>
            </li>
          </ul>
        </li>
      <% } else { %>
        <li>
          <a href="<%: Html.SiteMarkerUrl("Login") %>">
            <%: Html.SnippetLiteral("links/login", "Sign In") %>
          </a>
        </li>
      <% } %>
    </ul>
    <form class="navbar-search pull-right" method="GET"
      action="<%: Html.SiteMarkerUrl("Search") %>">
      <input type="text" id="q" name="q" class="search-query" placeholder="Search">
    </form>
  </header>
  <div class="content">
    <h1><%: Html.TextAttribute("adx_name") %></h1>
    <%: Html.HtmlAttribute("adx_copy") %>
  </div>
  <%: Html.EntityEditingMetadata() %>
  <%: Html.EditingStyles(new []
    {
      "~/xrm-adx/css/yui-skin-sam-2.9.0/skin.css"
    }) %>
  <script src="<%: Url.Content("~/xrm-adx/js/yui-2.9.0-combo.min.js") %>"></script>
  <%: Html.EditingScripts(new []
    {
      "~/xrm-adx/js/jquery-ui-1.8.18.min.js",
      "~/xrm-adx/js/tiny_mce/tiny_mce.js"
    }) %>
</body>
</html>