Pages - Menu

nopCommerce - Create New SQL Table / Domain Entity in the Cleanest Way

Scope

As our nopCommerce project advance through, finally it comes to a point where I need to create a new SQL table, a domain object to hold the properties and a service to perform CRUD (Create Read Update Delete) actions.

I am creating a Color class that will hold a SAP Color Code and Color Name. I need to create a service to lookup the Color Name by the Color Code. And this information needs to be available in the database.

Similar to my previous posts here and here, I am trying to do it the 100% clean way so my future upgrade path will be painless (by taking away the pain now). And I am not going to stress why this is important again. Different developers take different points of view in this topic and ideas could be extremely diverted.

Implementation

Domain Object

I create a new project follows the Nop.Core structure called TA.Core.


I create my domain class as usual. This one is straight forward.


Service Class

I need to create my color service that will utilize the domain object, I won't bother with the actual implementation but it looks something like this. It was fairly a Copy and Paste from Nop.Services.Catalog.ManufacturerService with Find and Replace job.


This class sits in my Custom Project, in my case, TA.Services.


Don't forget your dependency register, it sits inside the Service call, wherever you put the file in, you register in that project.


In my calling code, I will have to include this in my ctor. I am using the same example as my previous post, my TAImportManager.


SQL Table

We now need to create this SQL table ourselves. I call it dbo.color, but it is probably worth to prefix all the tables to group all the custom tables together, and avoid possible table name collision in future upgrades.

Mapping File

One of the file that is easily missed out in nopCommerce DAL area is this mapping file. If you forget this step, your code will compile but you will get runtime error when you try to access the object.

The entity type <type> is not part of the model for the current context.




We will put the mapping file in a blink blink shiny new project and you may guessed right - TA.Data


In the mapping file, we tell EF which table to look up and any fields mapping etc. 

ObjectContext

NopObjectContext - This is the object context that basically does all the database operations. I wouldn't go too technical about this, but the only thing we need to do is to make sure it knows where to find our ColorMap. If you look at this file carefully, in the OnModelCreating(), this line of code is to register all the types within the assembly.

var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()

Since our mapping is not inside the same assembly, we will create our custom NopObjectContext!!



DependencyRegister

We will register everything in the base by calling base method, then register everything in our custom assembly!!

Last but not least, we need to now register our TANopObjectContext in IoC.

We create a new DependencyRegistrar in TA.Data as follow. I copy and pasted the relevant sections from the Nop.Web project. Since we don't use http, I have changed the InstancePerHttpRequest() to InstancePerLifetimeScope().


Add reference

At this stage, if you build and run, you will still get error about entity not found.

The entity type <type> is not part of the model for the current context.

Didn't nop promise to register everything that implement the IDependencyRegistrar? Well, it might help if you tell it to. In the web project, we need to add reference to TA.Data.

Conclusion

As you can see, quite a big circle to do something very simple. The quickest and dirtiest approach would be adding files in the Nop.Data project, but if you are going to use nopCommerce intensively and with prospect of upgrading to future version, I rather take the pain away now.

In this exercise, I have touched no code / logics in the Nop Platforms. In my check-ins, the only thing I am checking into the Nop is Nop.Web.csproj (Added new references to the new projects) and NopCommerce.sln (Added new projects to the solution.

Fear not about passing your peer code review. :)


nopCommerce - Custom Service inherit from Core Service by Dependency Injection and new interface

Scope

Previously I was doing customization to override a method in custom class from core class. It provided the cleanest way to inherit from nopCommerce core services without any tampering to the core files. One thing that I couldn't do with the previous approach is to create new method or to overload a method. Today, we will go through this implementation.

Implementation

To begin with, we will create a new custom interface, and put the new methods (or overloading methods) that we need. The custom interface will inherit from the core interface.


The Custom class will implement the core class and inherit from the custom interface instead of the usual core interface. This part is quite crucial as we will see in a minute. Don't forget your usual ctor.



From my calling class (in this example, I am using a custom class of the ImportManager), instead of the usual property assignment, we will need to cast the concrete class to the custom interface, so it can be assigned to the private / protected property.


In IoC, we will need to register the custom class for the core interface!!


Wait a minute, how does it work? Shouldn't I register as custom interface? If you do, you will get an error, when there are other core classes that are still using the core interface with the private property still referencing the core interface. Something like a ctor doesn't match up exception.

The fact that custom class implement custom interface but custom interface also inherit from core interface, we created this chain in polymorphism that if I am a type of RacingCar, then I must be a type of Car. That's why the explicit cast in  _productService = (TAProductService) productService; would work.

Build the solution and run the code, my new method is being called.


Conclusion

As you can see, this is not very difficult but a little tricky when we are dealing with IoC and MVC at the same time. As demonstrated, it only required a little code to do the work.

Talking about racing cars, who went to the 2013 Sydney 500 Super Car last week?





How to Deploy nopCommerce solutions

Important Note  This document is obsoleted from nopCommere 3.3. 

The following document was created with nopCommerce 3.1.

Trying to deploy my local development site to staging, and the process seems not that straight away.

For my first time deployment with nopCommerce, I did the following and got my site working :)

  1. Build the project.
  2. Publish Nop.Web to the ~\Deploy directory.
  3. Publish Nop.Admin to the ~\Deploy\Administration\ directory.
  4. Move ~\Deploy\Administration\bin to ~\Deploy\bin. Replace exist files.
  5. Change database connection at ~\Deploy\Presentation\Nop.Web\App_Data\Settings.txt
  6. Copy all files from ~\Presentation\Nop.Web\Plugins to ~\Deploy\Plugins
  7. Copy images from ~\Presentation\Nop.Web\Content\Images to ~\Deploy\Content\Images
  8. Reinstall Plugins. Apparently all the plugins that were installed in dev are not installed on staging. It means the status of the installs, or any configurations I have applied to plugins on dev are not stored in the database but somewhere else. 
  9. Copy ~\Presentation\Nop.Web\App_Data\InstalledPlugins.txt to ~\Deploy\Nop.Web\App_Data\InstalledPlugins.txt to 

Really hated the step 8, wish there are better ways doing it. This post saved step 8. 


nopCommerce - Create Customized Service that inherit from Core Service by Dependency Injection

Scope

Provide the cleanest way to inherit from nopCommerce core services without any tampering to the core files.

In this exercise, the Nop.Services project is 100% untouched. Why is it so important? It benefits in many different ways but mostly for the reason of keeping the code neat and manageable. A nice and clear separation between custom code and core code.

This is written base on nopCommerce 3.1, the latest version as of today it is written.

Business Requirements


  • Discount should be calculated based on RRP (Product.Price), not the SpecialPrice or TierPrice. 
  • PriceCalculationService.GetFinalPrice() should still return the cheapest price out of the following 3 conditions:-
    • Cheapest discount off RRP
    • Special Price
    • Tier Price (if eligible / available)

Setup

We setup the price for the "Cooking for Two" book as follow. RRP $19, and Speical $15.



 We then apply discount rule 50% to the category.


50% discount applied to special price and now selling for $7.5. This is the default behavior of nopCommerce out of the box.


Implementation

I created a new project and added to the solution called TA.Services. It follows the same folder structure as Nop.Services and I created a new class CustomPriceCalculationService.



In TA.Services, I added reference Nop.Core and Nop.Services.



Similarly, in Nop.Web.Framework, I need to add reference to TA.Services.

Under Nop.Web.Framework, I changed this magic line in DependencyRegistrar.cs.

[EDIT] In TA.Services, I create a new DependencyRegistrar that implements IDependencyRegistrar. I will register my service to the interface. What it does is now everywhere in the project that require IPriceCalculationService, the IoC will return a concrete class CustomPriceCalculationService instead of the old PriceCalculationService.




In CustomPriceCalculationService, I need to inherit PriceCalculationService and implement IPriceCalculationService. Some usual Ctor methods override.

For those who interested in the actual implementation, I only made small changes to GetDiscountAmount and GetFinalPrice.




Now we are selling for $9.5 (50% off from $19). Hopefully still a happy customer!!


Conclusion

There are maybe better ways to implement this than what I have done here. eg. Use the plugin approach and make the use of Special Price configurable in the admin etc, but I couldn't wait to try this 100% clean way of customizations. 

Now I have a complete control on how I like to plug and play this customizations in a multi-tenant environment, or I can put more custom inheritance on top of already custom inheritance. The only thing I need to change is the DI which is pretty much given. 

As you can see, customization on services is a lot easier than controllers. Note how much troubles I had with the nopCommerce Customization with Controller Inheritance.

SEO - Site, Fetch and Submit

Scope

I have a developer background and know absolute nothing about how Google SEO works, besides the fact that I know it is important to get a site become popular in a Google search.

This is an important topic for me to learn in 2014, and I will slowly uncover the technical parts one after one by blogging them.

Search within Site

This is a very useful function to keep track of what pages are currently indexed by Google. This can help identify what pages are missing or what the page result will look like to users in a google search.

To perform a site search, the syntax is like this, type the whole string in a google search box.

site:www.domain.com

A result will look like this, it returns all pages of a domain. It works for both naked domain or subdomain.



Fetch and Submit

Fetch will force Google to crawl a URL. This is useful when you have just updated meta information or you have a new page that you might want Google to reindex.

Submit will force Google to reindex the page. Think of it like a commit command for your source code repository. After your fetch, you must submit to Google or Google will not reindex it.

These are done via the WebMaster Tool.
https://www.google.com/webmasters/tools





Should MVC ViewModel have methods?

Introduction

By design principle, ViewModel only contain properties, it certainly wouldn't have methods. However, there is always this temptation of convenience over convention, and to do this, we need excuses.

I have been working on MVC for a few years, but what is the big deal about it? In the old web form days, we always have this sort of ideas where front end developer will do layouts or javascripts, and then back end developers doing all these database calls and other logics. MVC and HTML5 bringing all these to the next level, View is predominantly used by front end developer, and they do not need to know anything about Controller or Repository, where a backend developer only responsible to populate the model and pass to the view then their jobs are done.

This is all achievable by having this separation of concern. With all these in minds, should MVC ViewModel have methods?

See it in sample

As usual, I pick example from first page result from google search.

Ref: http://forums.asp.net/t/1787772.aspx

The following method is inside a viewmodel. It claims that the method is for presentation only, therefore it is kinda legit.
   1: public IHtmlString Checked(double lower, double upper) {
   2:     return this.AverageRating > lower && this.AverageRating <= upper 
   3:         ? new HtmlString(" checked=\"checked\"") : null;
   4: }

But for real?

In my opinion, it is a no for me. If back end developer are to write this view model class, should I be concerned if the front end is using HTML5, JQuery or Flash?

My Alternative Solution

ViewModel

   1: public bool isAverage { get; set; }

Controller

   1: model.isAverage = (model.AverageRating > lower && model.AverageRating <= upper);

View

Checks isAverage and renders different HTML.


And you got the idea?

Verdict

I still have not encountered a situation where I have to put methods in a model, if you got one, you are welcome to fire to me. :)

The closest one that I've got is this one. Taken from an example that I have written half a year ago.


   1: public int? Age {
   2:     get 
   3:     { 
   4:         return (DateTime.Today.DayOfYear >= DOB.DayOfYear) 
   5:             ? (DateTime.Today.Year - DOB.Year) : (DateTime.Today.Year - DOB.Year - 1); 
   6:     }
   7: }

It is not a method, but a property that loaded with some logic to calculate the age base on other properties of the model. And it has no concern of presentation layer!!

Contribute to Mercurial in Simple Steps

Mercurial

Mercurial is a distributed source control management tool / system that allow developers around the globe to collaborate source codes. Recently engaged in an ecommerce project that utilize nopCommerce framework, which is an open source project. I found a little bug in there and made my very first contribution in open source. The nopCommerce is hosted on www.codeplex.com

Simple Steps

  1. Logon to CodePlex.
  2. Create a fork for the project
  3. Clone the fork
  4. Make local modifications.
  5. Check-in and commit to the local repository.
  6. Push changes from local fork to the remote server. In my case, it is https://hg.codeplex.com/forks/swon/austposthandlingchargefix
  7. After all changes are completed and checked. Create a pull request to merge the fork back to the project.

SVN Convention

Disregard the differences of the underlying technology how distributed source repository and non-distributed (classic?) repository works, a fork is basically a branch in SVN. Once you branch off, you can make local modifications that you do not conflict with the trunk (default). When you are done with the fork, you are then required to merge back and is done by the "pull request". In an open source environment, there will be some core developers of the project with higher access that will merge the changes.

Bucket name does matter on AWS S3

Scope


As some of you might know I have a second career as a photographer, and it is just natural for me to write my own website (Bootstrapped indeed!!). Currently having some issues with the existing web hosting so I began to migrate my site to be hosted in Amazon S3.

Migration Began


Went through the Web UI interface on AWS portal to upload files, set permission and enabled Static Website Hosting. All nice and sweet, had some issues to apply all public read policy to the bucket so I don't have to change permission per file basis. Once again, it wasn't difficult to find out how when we are in that era of information technology, a bit of search and I got the policy example up and running.

For those who curious here the code I have used. Version date cannot be changed or it will throw error. Why 2008???

   1: {

   2: "Version":"2008-10-17",

   3: "Id":"http referer policy example",

   4: "Statement":[

   5: {

   6: "Sid":"readonly policy",

   7: "Effect":"Allow",

   8: "Principal":"*",

   9: "Action":"s3:GetObject",

  10: "Resource":"arn:aws:s3:::mybucket/*"

  11: }

  12: ]

  13: }


What really got me and wasn't so obvious to me is that the bucket name is directly related to the domain I am going to use for CNAME redirect. What does it mean? Let's have a look.

At first I setup the bucket as "swphotography" as below.

swphotography

After I change my CNAME record in my DNS register, I get the error below.

error

With my given endpoint from s3, the site works fine without 404 error.

The error message was actually quite useful, especially the 2nd and 3rd lines helped me to resolve the problem.

The 2nd line is basically saying "bucket not found", and the 3rd line is saying BucketName: www.sunnyw.net.

Bucket Name Matters!!


Hello S3, I didn't setup the bucket name as www.sunnyw.net, it was swphotography! It had me thinking maybe the bucket name is related to the url, and maybe it uses it as a way to do bucket look up.

sunnyw.net

Copy the files over from the swphotography bucket to the www.sunnyw.net bucket, my site is up and running again!

Conclusion


It was a bit of effort but pretty happy with the result. As my usual whinging thing, perhaps they can provide a wizard tool for people who want to use CDN for static website hosting? It is not an uncommon strategy to host simple content sites and you may find articles about it on the internet easily. Extra bedside reading anyone?

CyberSource - The Magic Line(s) for Authorize and Capture

Scope


Working on integration with the CyberSource payment gateway that does direct payment (non-hosted option) on our online shop. Using the latest API version 1.93 as of today the article is written, and I followed their instructions and created a SOAP based WCF to connect to their Test Business Center (sandbox).

Problem


I followed copied their sample code, fiddle around to get it compile and submit the transaction with no error.

However, when I login to the test center, I only get authorize but not capture.

auth

(Authorize and Capture is explained in the CyberSource KB.)

Try to search around and finally find this pdf file. On page 176, it clearly explained on how to "request a sale". However, don't get so excited yet, it doesn't work if you just copy and paste the code. That's because they mix the documentations between their old Simple Order API Call and the SOAP API Call.

The 2 magic lines you need to get capture working (and authorize at the same time, essentially we are doing sale) as follow.

magic

Run the code and back to our sandbox, it is now trying to authorize and capture in the same transaction. Notice the green means successful, the red authorization in 2nd row stopped the transaction to proceed for capture, therefore it is neither red nor green color.

sale

Conclusion


It was a no brainer to work out the magic line(s) for the problem if you read the sample code carefully. I only wishful thinking that they would have put these 2 magic lines in the given sample code but I had my fun on a bit of code hunting and reading documentations today. Surely a better understanding of the CyberSource Payment Gateway.

nopCommerce Customization with Controller Inheritance

Scope


The following article is based on the latest platform of nopCommerce as of today, version 3.1.

Scenario


Trying to customize the view by adding some extra custom text, the goal is ideally we will not change the existing controller in the nopCommerce platform to allow easier future upgrade.

Normally, we will create a widget plugin to do that, nice and neat that plugin is isolated from the page controller and allow easy plug and play. This would work fine for most people.

However, in certain scenarios, if the works required to be done in the controller is more complicated like introducing new services, security control etc, then we will need to modify the controller.

The gotcha is we don't want to change the existing controller for future upgrade, with IoC and OO architecture, one would think it is easy just to create a new controller to inherit from the existing controller for custom works, but life is not that easy.

Customization


CoreController

In CustomerController, we need to set the Register() as virtual. And that is only change required in our core controller, so that you can override its functionalities.

VirtualRegister


CustomController

Let's take CustomerController as an example and I want to override the Register().

I created my own CustomerController file inside a folder called Custom.

 CustomerController in Explorer

I gave it a namespace of Nop.Web.Controllers.Custom, and inherit from the Nop.Web.Controllers.CustomController.

controller

You will need to set your constructor same as the parent controller, and use the keyword base to inherit from the base controller, pretty standard C# inheritance syntax.

constructor

You may override the Register() like the following. In this example, we changed the value of the ViewBag.Title only, but as you can imagine, you can initialize new objects or call other services, all be achieved.

OverrideRegister

RouteProvider

RouteProvider

In the Nop.Web project, Infrastructure\RouteProvider.cs, we need to map the controller to a different namespace, so our custom controller will be used in place of the parent one.

RouteProvider Custom

View

For demonstration purpose, I updated the view as follow, but a more professional way by using theme can be found here.

view

Result

Compile the solution and head to register page, it should look like this.

result


IoC

What about IoC? How will the CustomController get instantiated? That is already handled by the Nop.Web.Framework.DependencyRegistrar that will register all controllers in the assembly.

Conclusion


As demonstrated, it is not horribly difficult to do customizations in nopCommerce, I only wish it could be easier with the RouteProvider part where I can instead just use the IoC to change the constructor only, then the Visual Studio would be smart enough to pick up the custom controller during compilation.

nopCommerce Plugin - The partial view was not found

In an attempt of creating a new plugin, we have the following standard nopCommerce views and a "shared" view.

solutionexplorer

When dealing with view, I ran into an error like below where it cannot find the view for the plugin.

viewerror

In visual studio, view created by default with Build Action set to Content. This needs to be changed to Embedded Resource.

viewresource

The partial view also needed to be referenced by giving the fully qualified name space in the calling view.

FQ