Thursday, January 17, 2013

Day 1 - Porting nopCommerce to Linux

nopCommerce is an open source, feature rich, and production ready shopping cart and eCommerce solution. They are being used by a number of businesses all over the world as a platform of choice for their webstores. Out of the box, nopCommerce supports MS SQL Server and MS SQL Server Compact Edition as backend database engine. I was researching open source eCommerce solutions when I came across nopCommerce few months ago. NopCommerce peaked my interest as it is written using .Net Framework. While Mono project makes applications written on .Net framework cross platform, it lags behind .Net framework in development and lacks the latest features that .Net framework offers. When I first looked into nopCommerce, Asp.Net MVC 3 was not available for Mono and neither was Entity Framework. nopCommerce utilizes both of these features heavily. This made nopCommerce, an open source solution, not cross platform.

Recently, when the 3.0.3 development branch of Mono made both of these features available, I thought it'd be interesting to try and test Mono framework with its newly added Entity Framework and attempt to run nopCommerce under Linux.

This article will record the changes that were made to get rid of initial compile time errors for nopCommerce, run the application, and get to the Installation page.

Note: When modifying files in MonoDevelop that originate on Windows platform, and when a source control like Git is involved, it is best to not have MonoDevelop change line endings from windows to unix format to keep you commits clean.

Note: The code changes made during this experiment are available on GitHub at https://github.com/jimmy00784/nopCommerce-Linux-Mysql

The primary challenge I face is that in order to utilize Entity Framework and ASP.NET MVC 3 for .Net development, I had to upgrade the stable Mono 2.10.x to Mono 3.0.3 development release. I also had to upgrade MonoDevelop to 3.1.0 development release. This has broken the debugging capabilities from within MonoDevelop.

For porting nopCommerce, initially, I thought that simply switching the .Net Entity Framwork dlls with the Mono's dlls would be enough to run nopCommerce. I downloaded the source code from nopCommerce and loaded it in MonoDevelop. At first glance it didn't look as bad. Looking closely it becomes clear that System.Data.Entity supplied by the project would not work with Mono under Linux and there were dependency issues with EntityFramework and SqlServerCe dlls. I also downloaded the source for EntityFramework for Mono and planned to load EntityFramework as a project instead of simply adding the dll reference to the project. From earlier experience, I knew I'd be making some code changes to the EntityFramework to make it work with nopCommerce.

I added a solution folder for EntityFramework to nopCommerce solution and then added EntityFramework, EntityFramework.SqlServer, and EntityFramework.SqlServerCompact projects to it. For a quick sanity check, I compiled these new projects. EntityFramework complained that the delay sign key provided couldn't be used for assembly signing. That was easily fixed by providing the '-delaysign' compiler arguement. Recompiling didn't cause the same error but instead caused other code related errors, all of which are 'Warning as Error' which could also be fixed by unchecking the "Treat warnings as errors" settings for the project. This fix would also have to be applied to any other projects that complain in similar fashion. Also, the System.Data.SqlServerCe.dll supplied with EntityFramework.SqlServerCompact wasn't compatible with Mono on Linux. I was able to download the file from my Windows installation and that seemed to work ok for the purpose of achieving an error free compilation. The intention here was not to fix the EntityFramework project but to tighten or loosen just enough screws to run nopCommerce under Mono under Linux.

Build: 0 Errors, 54 Warnings.

That's a good place to be. Since EntityFramework project compiled, I commited the changes to the git repository so it would serve as a checkpoint in case I needed to revert any changes I make to the framework.

I replaced the EntityFramework references from the nopCommerce project and use the Entity Framework project as reference instead. Changes would be made only to Nop.Data project and the other projects under the Libraries solution folder for now. I also upgraded the projects from Mono / .Net 4.0 to .Net Framework 4.5 as that's the version EntityFramework would compile under due to other dependencies that are only available under .Net Framework 4.5. Recompiling gave only one error though enough to halt compilation of the project.

Libraries/Nop.Data/Extensions.cs(19,19): Error CS0234: The type or namespace name `Objects' does not exist in the namespace `System.Data'. Are you missing an assembly reference? (CS0234) (Nop.Data)

This was in reference to System.Data.Objects namespace needed on that class. A quick examination revealed that ObjectContext also had an issue and the only way to fix it was to include System.Data.Entity.Core.Objects in the project. This was coming from the EntityFrameworks project I included in the solution. Since I was tracking my changes in Git, I renamed all System.Data.Entity.Core to System.Data to see what it'd do.

Buid: 49 Errors, 34 Warnings.

Most of these were instances of EntityState and DbFunction references complaining for missing System.Data.Entity namespace directive. Many more errors were revealed once these errors were resolved but fortunately those required the same fix. Once all the errors were resolved, I tried replacing the references from EntityFramework.dll, System.Data.Entity.dll, and System.Web.Entity.dll with the EntityFramework project in their place. The changes made to the files under EntityFramework solution folder would only be commited to Git if replacing the Entity Framework references did not generated any namespace related errors.

As mentioned earlier, the projects under the Library solution folders would have to be upgraded to use .Net Framework 4.5 from Mono / .Net 4.0 profile since Entity Framework requires .Net Framework 4.5 features. Similarly projects under the Presentation solution folder would need to be upgraded to use .Net Framework 4.5 and references to EntityFramework.dll and System.Data.Entity.dll would need to be replaced with the project reference to EntityFramework project instead. Since all these projects compiled well without any errors, I commited the changes made to EntityFramework projects to Git.

System.InvalidOperationException
Storage scopes cannot be created when _AppStart is executing.

I had seen this before. A small change in Global.asax.cs file was needed to resolve this. Adding the following lines in the beginning of Application_BeginRequest function and including the necessary namespace references does the trick.

var ob = typeof(AspNetRequestScopeStorageProvider).Assembly.GetType("System.Web.WebPages.WebPageHttpModule").GetProperty("AppStartExecuteCompleted", BindingFlags.NonPublic | BindingFlags.Static);
ob.SetValue(null, true,null);

Giving it another run gave the following error.

System.IO.DirectoryNotFoundException
Directory '/home/karim/MonoDevelopProjects/nopCommerce_2.65_port/nopCommerce-Linux-Mysql/Presentation/Nop.Web/App_DataLocalizationInstallation' not found.

Now I was getting somewhere. Searching for the path reference in the code took me to the InstallationLocalizationService.cs file which passes the location string to webHelper.MapPath method. This took me to MapPath function in the WebHelper.cs file in Nop.Core project. The else block was written for Windows environment. This was done by the .Replace('/', '\\') method. Searching for that string pattern revealed two places total where this was used. I could check for OperatingSystem information before deciding to use the Replace function. Surrounding the code with "if(Environment.OSVersion.Platform != PlatformID.Unix)" should be sufficient. Recompiling gave no errors but running the project again did. It is a different error this time.

System.InvalidOperationException
The view 'Index' or its master was not found or no view engine supports the searched locations.
The following locations were searched:
~/Views/install/Index.aspx
~/Views/install/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Views/install/Index.cshtml
~/Views/install/Index.vbhtml
~/Views/Shared/Index.cshtml
~/Views/Shared/Index.vbhtml

At first glance it looked counterintuitive because ~/Views/Install/Index.cshtml did exist, but taking a closer look revealed that the system was looking for index with lower case "I" instead of upper case. I changed the URL in the address bar and used Install with upper case "I" and that landed me on the installation page.
After inspecting Global.asax.cs file at Application_BeginRequest, I found that one of the first thing the application does (ignoring the _AppStart fix) is EnsureDatabaseIsInstalled. Examining it revealed where the controller name install with a lower case "i" came from. I fixed the case there, recompiled and ran the application.

I now had the nopCommerce Installation Page.

7 comments:

  1. Your site, this post, redirected my iPad to a porn site. Maybe check what advertising you display. FYI.

    ReplyDelete
    Replies
    1. Will take necessary action. Thanks for bringing it to my attention.

      Delete
    2. It was a widget that I had used to allow for easy sharing of content. Perhaps they were hacked to serve advertisements and popups. It's been dealt with for now.
      Thanks

      Delete
  2. When I try to run on Mono and Linux this project I will get exception with sockets :( What's going on wrong? I don't understand. Would you help me to solve this issue?
    http://mmm2011.sg/img/nop-problem.png

    ReplyDelete
    Replies
    1. Try running in Release mode. There may be an issue with symlink of xsp4 webserver.

      Delete
  3. Custom nopCommerce development company; we integrate all the nopCommerce functionalities in your eShop that perfectly suit your needs & fit the purpose.

    ReplyDelete
  4. Thank you for sharing such a great information about nopCommerce.

    ReplyDelete