I am sure many of you will loooove this article.
IT IS POSSIBLE TO GET THE COMMERCE STARTER KIT TO WORK IN MEDIUM TRUST!!!
You can follow the instructions below, alternatively you can download the C# code from my SkyDrive:
I have been now fighting for a while to get the wonderful ASP.NET Commerce Starter
Kit 2.0 to work on my ISP Shared hosting server.
At first I thought it was a lost battle and started coding the CSK without SubSonic, Entreprise Library or any of this fancy stuff that requires full trust to run properly.
But after battling harder, I noticed a few things that changed my life yesterday and let me share my findings with you all!
Here is how I got there :
1. I added this line in the CSK web.config so it would simulate my hosting service environment on my dev machine :
<trust level="Medium" />
I also prevented SubSonic from using the Entreprise Library data access and to use the more supported SqlDataProvider (not sure this made a difference but I would like to mention it) :
<SubSonicService defaultProvider="ELib2DataProvider">
<providers>
<!--<add name="ELib2DataProvider" type="SubSonic.ELib2DataProvider, SubSonic" connectionStringName="CommerceTemplate"/>-->
<add name="ELib2DataProvider" type="SubSonic.SqlDataProvider, SubSonic" connectionStringName="CommerceTemplate" />
</providers>
</SubSonicService>
2. I updated the ATLAS stuff with the latest from Microsoft (optional):
http://ajax.asp.net/
Notes :
- With that step more changes to the web.config are required (cf the web.config of the ajax web extensions).
- Also I moved the ScriptManagers to the master pages (admin and site) and removed them from other pages, that way you always have ajax enabled pages :)
- There is also an attribute that you need to remove from the ScriptManager or it won't compile.
- One last thing you also have to replace the "Mode" attribute of all your UpdatePanels and change it to "UpdateMode".
config.GetSection... to ConfigurationManager.GetSection
And rem out the line that says :
Dim config As System.Configuration.Configuration = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath)
This will try to access your web.config file and save it, which is NOT allowed in partial trust.
The only pages that use this to write to the file are the Payment, Shipping and Tax configuration pages in the admin. I have simply disabled the "config.save" (i.e. rem'd it out) in those pages and you just need to go and configure those values manually in the web.config before you publish the code.
4. Next thing is to get rid of the eWorld.UI assembly all together cause it needs full trust to run and to replace the controls used in the CSK by nice new shiny AjaxControlToolkit controls (NumericBox to TextBox and Calendar are the only ones that I found in the project). Best to delete the eWorld.UI.dll from the bin folder and compile to see where we have to make the changes :o)
In order to use the AjaxControlToolkit you must put the AjaxControlToolKit dll in your bin folder and register it in the page :
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
Then you can replace everywhere it says "ew:NumericBox" by "asp:TextBox" and get rid of the :
<%@ Register Assembly="eWorld.UI" Namespace="eWorld.UI" TagPrefix="ew" %>
Finally for the calendar, replace :
<ew:calendarpopup id="txtExpirationDate" runat="server"></ew:calendarpopup>
By:
<asp:TextBox ID="txtExpirationDate" runat="server"></asp:TextBox>
<ajaxToolkit:CalendarExtender ID="CalendarExtender1" runat="server" TargetControlID="txtExpirationDate" Format="dd/MM/yyyy" />
Another thing, once you have done that some of your code behind files will stop working and you will have to replace the old "PostedDate" or "SelectedDate" of the old calendar controls by the "Text" property of your textbox.
Also everytime you need to set a datetime datafield just do DateTime.Parse(textbox.Text) instead of the old eWorldUIOldTextBox.SelectedDate.
There will also be occurrences of this sort of thing which will not pass the compilation:
calEnd.SelectedDate = DateTime.Today
Just replace it with:
calEnd.Text = String.Format("{0:dd/MM/yyyy}", DateTime.Today)
Or this sort of thing :
calEnd.SelectedDate
Replace it with :
DateTime.Parse(calEnd.Text)
There might be more small code changes that I forgot to document here but I will let you find out by yourself, you've got the general idea!
Once the project compiles locally with those changes and in medium trust (cf step 1) then you can publish it (Build > Publish Website) and compile it to a location on your hard drive. Copy the files to your ISP with the correct DB connection strings and that's it! (I agree it's actually quite a lot!)
If you need the code, drop me a line with your email address and I will send it to you.
I have tried to look at contributing in CodePlex for the CSK but the lack of documentation on how to do that made me loose motivation...
On the other hand, the changes that I have made so far may have other impacts on other functions of the CSK so following my advice is at your own risk, you are responsible for any change you make to the code :o)
From what I have seen so far though, everything works like a charm on a shared hosting server!!!
Good luck and let me know your feedback.
Cheers!
UPDATE 07/01/2008: WHAT TO DO WHEN YOU ARE GETTING THE INFAMOUS
"The SqlParameterCollection only accepts non-null SqlParameter type objects, not QueryParameter objects" ERROR
I received quite a few emails about this as it is a problem when using the CSK code and the solution is here:
You need to edit the OrderController.vb (or .cs) to include this function:
Public Shared Function GetDBCommand(ByVal objSubCom As SubSonic.QueryCommand) As DbCommand
Dim objDbCom As DbCommand
Dim objSqlCon As New SqlConnection(ConfigurationManager.ConnectionStrings("LocalSqlServer").ToString)
objDbCom = objSqlCon.CreateCommand()
objDbCom.CommandText = objSubCom.CommandSql
objDbCom.CommandType = objSubCom.CommandType
Dim par As QueryParameter
Dim objSqlParam As SqlParameter
For Each par In objSubCom.Parameters
objSqlParam = New SqlParameter
objSqlParam.DbType = par.DataType
objSqlParam.ParameterName = par.ParameterName
objSqlParam.Value = par.ParameterValue
objDbCom.Parameters.Add(objSqlParam)
Next
Return objDbCom
End Function
Then replace all the lines that say:
order.GetUpdateCommand(Utility.GetUserName()).ToDbCommand
With this line calling the new function bypassing the subsonic call:
GetDBCommand(order.GetUpdateCommand(Utility.GetUserName()))
The ToDbCommand is the one causing the error and it's a Subsonic function. It is only throwing the error when using the SqlProvider to connect to the DB (from the SubSonic dll). So the new GetDBCommand that I wrote is a workaround that bypasses that function...