Controllers & ViewComponents

Smartstore modules are pure MVC projects. This means that normal controller classes can be implemented using the MVC pattern. Since varying fields of application often require repetitive tasks, we have created base controllers following the DRY principle. These take care of many tasks and can of course be used to implement your own controllers.

The base controllers are located in the Controllers directory of the Smartstore.Web.Common project. By including the most important attributes and implementing auxiliary methods, they keep controllers consistent and eliminate redundancy.

SmartController

The SmartController is the base controller that all other controllers implement. The provided functionality and members are therefore present in all controllers. Since the SmartController is the lowest possible abstraction, it should not be used directly. It is better to use controllers that implement the SmartController as a base for your own controller, such as the PublicController or the AdminController.

Members

Logger

Can be used to log errors or information.

Logger.Error(ex);

For more information, see Logging.

T

Provides the Localizer using the T shortcut that can be used to access localized resources.

T("Admin.Common.OK")

For more information, see Localization.

Services

Provides the ICommonServices service collection using the Services shortcut.

var customer = Services.WorkContext.CurrentCustomer;

For more information, see ICommonServices.

Methods

Widget, View & Component rendering

The following methods can be used to invoke a view and return its HTML result content as a string. This can be useful when content needs to be returned by AJAX requests.

  • InvokeViewAsync

  • InvokePartialViewAsync

  • InvokeComponentAsync

var html = await InvokePartialViewAsync("MyPartialView", myPartialViewModel);
Notify

Send a message to the user using the NotifyInfo, NotifyWarning, NotifySuccess, NotifyError and NotifyAccessDenied shortcuts.

NotifyError("Something went wrong during this operation.");
Redirection

The RedirectToReferrer method redirects users to the page they came from.

public async Task<IActionResult> MyAction()
{
    // ...
    return RedirectToReferrer();
}

ManageController

The ManageController provides auxiliary methods, that can be used to configure domain entities and settings. Since this is mostly used in the admin area, we recommend basing your controller on the AdminController instead of the ManageController directly. It implements the ManageController and adds more auxiliary methods relevant to the admin area.

All previous examples can be applied to controllers based on the ManageController, because it implements the SmartController.

Methods

AddLocales / AddLocalesAsync

Please make sure you understand the concept of localizable entities before reading on.

To prepare models for localizable entities, a localized model must be added for each enabled language in the store. This model must contain all values of the localizable properties and be able to receive them for postback. Localized models must implement the ILocalizedModel<MyLocalizedModel> interface, where MyLocalizedModel contains all the properties of the localized values to be stored. This ensures that the List<MyLocalizedModel> Locales property is always available.

The following call initializes the model, as long as it doesn’t contain any entities. This is the case for Create methods.

AddLocales(model.Locales);

If localized entities already exist, for example, when using Edit methods, the localized model can be initialized like this:

var myEntity = await _db.MyEntities().FindByIdAsync(id, false);

AddLocales(model.Locales, (locale, languageId) =>
{
    locale.MyLocalizedProperty = myEntity.GetLocalized(x => x.MyLocalizedProperty, languageId, false, false);
});
SaveStoreMappingsAsync

Please make sure you understand the concept of Multistores before reading on.

Entities can implement the IStoreRestricted interface, which allows the user to restrict displaying an entity to specific stores. IStoreRestricted requires the implementing entity to have the following property:

public bool LimitedToStores { get; set; }

The model must provide the ability to hold the selected store IDs. The store restriction can be further configured by the store owner and is typically implemented in the model as follows:

[UIHint("Stores")]
[AdditionalMetadata("multiple", true)]
[LocalizedDisplay("Admin.Common.Store.LimitedTo")]
public int[] SelectedStoreIds { get; set; }

To save the store mapping defined by the store owner you can then use the following call:

var myEntity = await _db.MyEntities().FindByIdAsync(id, false);
await SaveStoreMappingsAsync(myEntity, model.SelectedStoreIds);
SaveAclMappingsAsync

Please make sure you understand the concept of ACL before reading on.

Entities can implement the IAclRestricted interface, which allows the user to restrict displaying an entity to specific CustomerRoles. IAclRestricted requires the implementing entity to have the following property:

public bool SubjectToAcl { get; set; }

The model must provide the ability to hold the selected customer role IDs. ACL restriction can be further configured by the store owner and is typically implemented in the model as follows:

[UIHint("CustomerRoles")]
[AdditionalMetadata("multiple", true)]
[LocalizedDisplay("Admin.Common.CustomerRole.LimitedTo")]
public int[] SelectedCustomerRoleIds { get; set; }

To save the ACL restrictions defined by the store owner you can then use the following call:

var myEntity = await _db.MyEntities().FindByIdAsync(id, false);
await SaveAclMappingsAsync(myEntity, model.SelectedCustomerRoleIds);
GetActiveStoreScopeConfiguration

When configuring settings, the store owner needs to be able to define different settings for each store. This can be done by adding the StoreScope ViewComponent to the view. Then the GetActiveStoreScopeConfiguration method can be used in controller methods to access the store id set by the store owner in the StoreScope setting.

AdminController

All previous examples can be applied to controllers based on the AdminController, because it implements the ManageController.

The AdminController adds the following attributes:

Attribute
Description

Area("Admin")

Specifies Admin as area of the controller.

AutoValidateAntiforgeryToken

An attribute that causes antiforgery token validation for all insecure HTTP methods. An antiforgery token is required for HTTP methods other than GET, HEAD, OPTIONS, and TRACE.

AuthorizeAdmin

Checks whether the current user has permission to access the administration backend.

ValidateAdminIpAddress

Verifies that the IP address being used matches one of the addresses defined in AdminAreaAllowedIpAddresses from the SecuritySettings.

PublicController

The PublicController implements the SmartController and adds the following attributes:

Attribute
Description

CookieConsent

Checks if the visitor has already allowed the use of cookies and opens the CookieManager if not.

PreviewMode

Enables the use of preview mode in the public store as long as preview mode is enabled in the backend.

CheckStoreClosed

Checks if the store has been closed by the admin and returns a redirect result to the StoreClosed action.

AuthorizeShopAccess

Checks whether the current user has permission to access the shop.

TrackActivity(Order = 100)

Saves current user activity information including the date, IP address and the visited page, in the database.

CheckAffiliate(Order = 100)

Checks if a visiting customer was referred to the shop by an affiliate by analyzing the request query.

SaveChanges(

typeof(SmartDbContext),

Order = int.MaxValue)

Saves all pending changes in a DbContext instance to the database after an action method has been executed.

ViewComponents

ViewComponents is a feature that was added to ASP.NET Core. They provide developers with the means to create recurring components that are used in the application GUI. Similar to controllers, the SmartViewComponent base class adds ways to perform repetitive tasks and some auxiliary methods.

Members

Logger

Can be used to log errors or information.

Logger.Error(ex);

For more information, see Logging.

T

Provides the Localizer using the T shortcut that can be used to access localized resources.

T("Admin.Common.OK")

For more information, see Localization.

Services

Provides the ICommonServices service collection using the Services shortcut.

var customer = Services.WorkContext.CurrentCustomer;

For more information, see ICommonServices.

Methods

Results

There are three different ways to return rendered content using the SmartViewComponent:

  • Content: Returns a result that renders HTML encoded text.

  • HtmlContent: Returns a result that renders raw (unencoded) HTML content.

  • View: Returns a result that renders the partial view with an explicit name, or default, if none is specified.

public IActionResult MyMethod()
{
    // ...
    return View();
}
Notify

Send a message to the user using the NotifyInfo, NotifyWarning, NotifySuccess, NotifyError and NotifyAccessDenied shortcuts.

NotifyError("Something went wrong during this operation.");

Events

PublishResultExecutingEvent

In a ViewComponent that implements SmartViewComponent, the content is returned as a IViewComponentResult using one of the rendering methods (see Results). They call the internal method PublishResultExecutingEvent, which publishes a ViewComponentResultExecutingEvent that developers can subscribe to. This allows them to react to the rendering of the component. The ResultExecutingEvent is always published just before a view component is about to render the view. This event basically replaces the OnActionExecuted and OnResultExecuting child action filters of the classic MVC.

public async Task HandleEventAsync(ViewComponentResultExecutingEvent message)
{
    var componentType = message.Descriptor.TypeInfo.AsType();

    // Only do stuff when InterestingViewComponent is rendered
    if (componentType == typeof(InterestingViewComponent))
    {
        // Do stuff
    }
}
ViewComponentInvokingEvent

The ViewComponentInvokingEvent is published just before a view component is about to be created or its model is about to be prepared. This event basically replaces the OnActionExecuting child action filter of classic MVC.

Unlike the ViewComponentResultExecutingEvent, which is always published implicitly by the SmartViewComponent, this event must be published explicitly by the view component authors. This is best done just before model creation.

The component author should check if the model property has been assigned a non-null value by any event consumer. In this case, model creation should be skipped and an externally provided model should be used instead.

var myComponentEvent = new ViewComponentInvokingEvent<MyModel>(ViewComponentContext);
await _eventPublisher.PublishAsync(myComponentEvent);

Last updated

Was this helpful?