vu3lo

vu3lo

Matthew Boniface

I am a developer living and working on the Sunshine Coast, Australia. Most topics here are focussed on programming (MVC / ASP.Net / C#) and Episerver.

Explore Tagged Posts
Last Seen Blogs
Statistics

We looked inside some of the posts by vu3lo and here's what we found interesting.

Inside last 20 posts
Time between posts
8 months
Number of posts by type
Photo
0
Video
0
Audio
0
Text
7
Chat
0
Answer
0
Link
0
Quote
0
Fun Fact

Tumblr paired up with Humans of New York to raise money for Hurricane Sandy relief.

vu3lo·2 years agoText

Had been struggling to figure out how to include our custom field extension methods on our product content types in the asset panel (right hand panel) search for editors.

We just had a simple extension method on the product content type that we used a custom CatalogContentClientConventions to include it in the Find index. 

But to ensure these fields are used in the Asset Panel for editors searching, the solution is to extend the EnterpriseCatalogSearchProvider class. The outcome looks something like this:

[SearchProvider]
public class CustomEnterpriseCatalogSearchProvider : EnterpriseCatalogSearchProvider, ISortable
{
   public CustomEnterpriseCatalogSearchProvider(LocalizationService localizationService, IEnterpriseSettings enterpriseSettings, IContentTypeRepository<ContentType> contentTypeRepository)
       : base(localizationService, enterpriseSettings, contentTypeRepository)
   {
   }

   public CustomEnterpriseCatalogSearchProvider(LocalizationService localizationService, IEnterpriseSettings enterpriseSettings, IContentTypeRepository<ContentType> contentTypeRepository, UIDescriptorRegistry uiDescriptorRegistry)
       : base(localizationService, enterpriseSettings, contentTypeRepository, uiDescriptorRegistry)
   {
   }

   public CustomEnterpriseCatalogSearchProvider(LocalizationService localizationService, ISiteDefinitionResolver siteDefinitionResolver, IContentTypeRepository contentTypeRepository, UIDescriptorRegistry uiDescriptorRegistry)
       : base(localizationService, siteDefinitionResolver, contentTypeRepository, uiDescriptorRegistry)
   {
   }

   protected override IQueriedSearch<IContentData, QueryStringQuery> AddContentSpecificFields(IQueriedSearch<IContentData, QueryStringQuery> query)
   {
       return base.AddContentSpecificFields(query)
           .InField(x => ((CustomProduct)x).GetSpecialValue());
   }

   /// <summary>
   /// Change to be first search provider (otherwise other instances might be selected first)
   /// </summary>
   public new int SortOrder => 1;
}

In the above example the overridden AddContentSpecificFields method will add the “GetSpecialValue()” to the asset panel catalog search query.

This should also work for CMS content search too. But instead you would extend EnterprisePageSearchProvider for pages, EnterpriseBlockSearchProvider for blocks, or EnterpriseMediaSearchProvider for media.

0 notes · See All
vu3lo·2 years agoText

Episerver Commerce with Find integration will, by default, reindex content when a price or inventory update occurs.

This is coordinated by the CatalogContentEventListener class. Inside this class implementation there is are methods “IsReindexingContentOnPriceUpdates” and “IsReindexingContentOnInventoryUpdates” which return their respective boolean as to whether it should reindex.

The problem I had was to figure out how to change these settings. Because I am yet to find a simple appSetting or other property to set, here is how I have overridden their settings:

[ServiceConfiguration(ServiceType = typeof(CatalogContentEventListener))]
public class CustomCatalogContentEventListener : CatalogContentEventListener
{
   public CustomCatalogContentEventListener(ReferenceConverter referenceConverter, IContentRepository contentRepository, IClient client, CatalogEventIndexer indexer, CatalogContentClientConventions catalogContentClientConventions)
       : base(referenceConverter, contentRepository, client, indexer, catalogContentClientConventions)
   { }

   public CustomCatalogContentEventListener(ReferenceConverter referenceConverter, IContentRepository contentRepository, IClient client, CatalogEventIndexer indexer, CatalogContentClientConventions catalogContentClientConventions, PriceIndexing priceIndexing)
       : base(referenceConverter, contentRepository, client, indexer, catalogContentClientConventions, priceIndexing)
   { }

   public override bool IsReindexingContentOnPriceUpdates()
   {
       return false;
   }

   public override bool IsReindexingContentOnInventoryUpdates()
   {
       return false;
   }
}

Hope this helps someone (or myself when I re google this in the future).

0 notes · See All
vu3lo·5 years agoText

EPiServer Commerce has substantial processes which rely on workflows. In many scenarios, like on a simple consumer website, you may get away without modifying or configuring these workflows beyond their defaults.

But on my current project I needed to simply disable payment processing in the CartCheckout workflow. And there is an API method in Mediachase.Commerce.Orders.OrderGroup that facilitates this:

// Summary:
//     Runs the specified workflow.
//
// Parameters:
//   name:
//     The name.
//
//   throwException:
//     if set to true the exception will be thrown and should be handled by the
//     caller.
//
//   param:
//     The additional input parameters.
public virtual WorkflowResults RunWorkflow(string name, bool throwException, Dictionary<string, object> param);

For my situation setting IsIgnoreProcessPayment to true when running the CartCheckout workflow, this is my simplified code that was required:

var workflowParams = new Dictionary<string, object> { { "IsIgnoreProcessPayment", true } }
var results = cartHelper.Cart.RunWorkflow(OrderGroupWorkflowManager.CartCheckOutWorkflowName, true, workflowParams);

I hunted for examples of how to set IsIgnoreProcessPayment so thought it deserved a blog post.

0 notes · See All
vu3lo·5 years agoText

In EPiServer Commerce prices are loaded via the IPriceService and IPriceDetailService. I needed to customise the IPriceService logic but just to tweak the price filtering and still intend to call the default IPriceService internally to reuse the base functionality.

This is where confusion ensues, how does one configure the dependency resolver (StructureMap) to return my custom price service implementation which itself has a dependency on the same IPriceService interface? Turns out StructureMap has a method called EnrichWith to achieve this.

So I have my implementation called “CustomPriceService” and the default EPiServer implmentation is “PriceServiceDatabase“. My CustomPriceService constructor looks like this:

public CustomPriceService(IPriceService defaultPriceService)
{
this._defaultPriceService = defaultPriceService;
}

Now I have the local field _defaultPriceService that I can call for default functionality throughout my custom implementation and it still retains the injected abstraction for unit testing purposes.

To configure StructureMap all that is needed is:

container.For<IPriceService>().Use<PriceServiceDatabase>().EnrichWith((context, systemPriceService) => new CustomPriceService(systemPriceService));

When an IPriceService dependency is resolved StructureMap will get the default EPiServer Commerce “PriceServiceDatabase” and then create my “CustomPriceService” passing the PriceServiceDatabase into the constructor.

If your constructor needs other dependencies you can use the “IContext” that EnrichWith provides, for example:

container.For<IPriceService>().Use<PriceServiceDatabase>().EnrichWith((context, systemPriceService) => new CustomPriceService(systemPriceService, context.GetInstance<ICurrentMarket>()));

Hopefully this will help anyone trying to figure out how to get StructureMap to configure a dependency for a given type to itself have a dependency on the same type.

0 notes · See All
vu3lo·6 years agoText

Update (28 Dec 2015): I have since noticed that this information now seems to be officially documented at http://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Globalization/localizing-the-user-interface/

It could be something I simply missed, but I spent a fair amount of time searching the web for how to override the text an EPiServer editor sees for content types and properties. Perhaps this is so obvious that no one else needed documentation or examples on the web to figure it out? Ultimately though, I found the answer in the Alloy sample website code.

I’m currently using EPiServer 8 (8.2 to be precise) and found placing the following in a lang xml file will override a custom content type and properties:

<contenttypes>
  <HomePage>
    <name>Hemsida</name>
    <description>Startsidan för webbplatsen</description>
    <properties>
      <MainContentArea>
        <help>Huvudinnehållsområdet till att omfatta hemsidan widgets</help>
      </MainContentArea>
    </properties>
  </HomePage>
  <ContentMetadataBlock>
    <name>Innehåll Metadata Block</name>
    <properties>
      <Description>
        <caption>Beskrivning</caption>
        <help>Meta beskrivning taggar arbetar med titeln att locka besökare till dina sidor. Standard SEO regeln är att hålla dina metabeskrivningar till 150 tecken eller mindre.</help>
      </Description>
    </properties>
  </ContentMetadataBlock>
</contenttypes>

In this case I’m overriding the HomePage’s “name”, “description” and its “MainContentArea” properties “help” text with the Swedish language version. And below this I demonstrate a block having similar text overridden.

Now an editor with the UI set to Swedish will find property names and descriptions have been customised for them.

From what I see in the Alloy site, you can also do generic overrides for common properties throughout your codebase by using a base type or even an interface, such as IContentData:

<contenttypes>
  <icontentdata>
    <properties>
      <!-- SitePageData -->
      <disableindexing>
        <caption>Disable indexing</caption>
        <help>Prevents the page from being indexed by search engines</help>
      </disableindexing>        
      <!-- Common properties-->
      <mainbody>
        <caption>Main body</caption>
        <help>Main editorial content of the page</help>
      </mainbody>
    </properties>
  </icontentdata>
</contenttypes>

Hopefully this helps someone else to more easily discover this.

0 notes · See All
vu3lo·7 years agoText

An EPiServer website I worked on had logging working well until it [seemingly] randomly stopped working. I reviewed changes in our configurations and could not trace a cause for the sudden failure.

I proceeded to enable log4net’s own logging which is done by adding this to your web.config:

<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add
name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="C:\log4net.txt" />
</listeners>
</trace>
</system.diagnostics>

This log revealed the following:

log4net: XmlConfigurator: configuring repository [log4net-default-repository] using file [C:\Dev\Project1\Trunk\Src\Web\web.config]
log4net: XmlConfigurator: configuring repository [log4net-default-repository] using stream
log4net: XmlConfigurator: loading XML configuration
log4net: XmlConfigurator: XML configuration does not contain a <log4net> element. Configuration Aborted.

With EPiServer, this should be using it’s default EPiServerLog.config rather than log4net’s default web.config location - hence why it’s not finding the <log4net> element.

It took me a little experimentation and searching before I realised the problem was caused because I referenced log4net in our Global.asax.cs. This causes it to setup log4net prior to EPiServer determining the EPiServerLog.config file. Once I removed that, it all worked again!

0 notes · See All
vu3lo·7 years agoText

If you have an annoying issue where your CI (TeamCity) web deployments were not transforming some configs, you’re not alone. And I might have found a reason why:

Mine in particular was transforming a few configs (web.config, episerverlog.config etc) whilst not transforming some (connectionstrings.config, episerverframework.config and episerver.config).

It turns out that the Web.csproj file had them specified differently. The ones that were working looked like this:

<Content Include="EPiServerLog.config">
<SubType>Designer</SubType>
<TransformOnBuild>true</TransformOnBuild>
</Content>

While the configs that did not work had only:

<Content Include="EPiServerFramework.config" />

So I’ve added in the <TransformOnBuild>true</TransformOnBuild> and they now work :)

1 notes · See All