So just after a year of being in Australia I have finally managed to organise my first industry presentation on Commerce Server 2009. I will be presenting at SharePoint Saturday Melbourne on Saturday 14th November. My talk will cover an introduction to using Commerce Server 2009 alongside MOSS FIS. This follows on from the great success the Commerce Server product team had presenting this topic on at the SharePoint Conference in Vegas.
So if you would like to come along and here my talk, please register ASAP on the SharePoint Saturday website http://www.sharepointsaturday.org/melbourne/default.aspx – places are free but limited.
Alternately if you are not local to Australia there are some other great presentations forthcoming on Commerce Server 2009 - including a presentation by Commerce Server Architect Scott Cairney at TechEd EMEA, check out the Commerce Server product team's blog for more details: http://blogs.msdn.com/commerce/archive/2009/10/24/teched-emea-2009-commerce-server-session-detail.aspx
In my spare time I am busy preparing Commerce Server resources for the new http://www.CSDevWiki.com and some forthcoming public speaking events. So with all of these resources ready and prepared around Commerce Server 2009 development, SharePoint Commerce Services, and multi-channel e-Commerce development I think to myself why not try and share these around. So if you are in the Asia Pacific Region (and I intend to travel back to London for a holiday at some point next year too) and would like a speaker or trainer for your event, albeit a SharePoint user group, private Commerce Server training, etc. Please feel free to get in touch. I am happy to present from a variety of topics on the Commerce Server platform, so do let me know your interests.
In the meantime check out http://www.CSDevWiki.com over the next few days where I'll be posting a whole load of resources around Commerce Server development.
With Commerce Server 2009 R2 progressing through its CTP at an expediential rate, I am keen to start looking at deployment scenarios for one of its key features – distributed application services. The R2 release has separated the application tier into WCF-based services, meaning that you will no longer be tied to ASP.NET or SharePoint based front ends for deployment. The to-be released Out-of-the-box functionality will now allow for easier to deploy multi-channel commerce scenarios in most digital platforms, ranging from interactive-TV, kiosks, and smart phones – really anything with an Internet connection.
To help get some tutorial and examples of the ground, I am looking for a project that can make use of this technology that I can use as a tutorial basis and case study for the forthcoming release. So if you are keen to get an e-commerce scenario for a kiosk, multi-touch PC*, Microsoft Surface*, or even something smart like an geographical presence app on a platform such as the I-Phone, and have the hardware but not the know-how, please get in touch as I am keen to help you get your project up and running, and get some good tutorials up and running for this next-generation e-Commerce platform.
*applications will be built in WPF, or Silverlight 3. All technology will be Microsoft based, or in the case of I-Phone apps will be based on Mono.
One of the biggest successes of any technology platform is the success of its communities that back it, and in my opinion this has been one of the biggest contributing factors of SharePoint's ever growing popularity. So in contract if you look at the community effort for a product such as Commerce Server, which itself is a niche – but one that is now starting to head into mainstream with the achievements of Commerce Server 2009 and its alignment with both the SharePoint family, and moving into the WCF, and multi-platform multi-channel deployment with the R2 release.
It is now great to see that throughout 2009 the number of people visiting the MSDN forums and asking question is increasing – and so are the number of people answering them. I have read some really good blog posts equally, and Glen Smith has recently published a book on the Commerce Server platform.
The community is ever growing and a lot of great insight and documentation is now online to support people with setting up, and building a Commerce Server solution, yet this information is disparate and still not that easy to find. This is why I was really glad to see that another Sydney based Commerce Server developer, Ducas Francis, has now set up a community-based Commerce Server development wiki - a place whereby tutorials and enhancements on technical documentation can be centralised and made readily available to the wider public. The new site can be found at http://www.csdevwiki.com/ and although the content currently is sparse – I would strongly recommend that as a community we pull together, and help Ducas populate the site with content that is current and relevant, supporting that of MSDN and our community blog efforts.
So if you are a Commerce Server developer, evangelist, MVP – or even on the MS Commerce Server product team, and have a spare 5 mins in your day please help out our community and extend the wiki that little bit more!
Recently on the MSDN forums a question was raised about how to re-style the Commerce Server catalogue when using Commerce Server 2009 within a SharePoint environment. Those who are familiar with SharePoint and web-parts may have reasonable knowledge around the use of XSLT and apply a style sheet to the web parts parameters, however out –of-the-box this becomes a little challenging for people new to the product.
To demonstrate how to achieve a basic XSLT transformation, I will demonstrate splitting the catalogue query web part into 2 rows... (N.B.: my use of tables here is not best practice; however it is the simplest method of demonstrating this).
So the first step is to get yourself into the page in edit mode, so that you can see the chrome around the web-parts. If you are in the correct place you should see a screen similar to this:
The web part chrome itself contains an edit menu, and when clicking it you will be presented with the following display on the right side of your screen:
The menu itself is larger than this, but the first four fields are the once most important to this tutorial, and are as follows:
Template To Display – this is a drop down box which allows you to pick one of the out-of-the-box templates, or templates previously created by you.
Template Details – when clicked this will open a modal text box, which you use to modify or edit your templates.
Template Properties - Allows you to select which properties of the products you wish to display, this also includes those of variants.
Save Current Template to Library – Allows you to change the name under which you save the modified template.
So to change the pre-existing template you need to click into the Template Details box, and click on the [...] button to open up the model input box, which will be similar to this :
The code inside here is actually XSL – the XML version of a style sheet and actually dictates how and what is displayed within the product query web part. If you are not familiar with XSL, don't worry as simply changes can easily be achieved with knowledge of HTML only, however more complex logical changes will require you to invest sometime in grasping the XSL concepts. Unfortunately MOSS does not give you the best editing environment for XSL changes, so I would recommend copy the contents of this box, and moving it into an XML Editor (I use Altova XML Spy, which is a commercial product, but there are free tools available too).
Once you put the contents of this windows in a more presentable environment you will start to see the majority of this code is simply XHTML, which can be changed to your liking:
So simply all you need to do is make the stylistic tweaks you like, which in my case is creating a table attribute, and placing the existing divs into 2 columns – which looks something like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="_category"/>
<xsl:param name="DefaultImagesRepository"/>
<xsl:param name="_catalog"/>
<xsl:template match="/products">
<div id="divCategoryMain">
<XsltAction Id="Pager" Type="Microsoft.Commerce.Portal.UI.Catalog.WebControls.PagerXsltAction, Microsoft.Commerce.Portal.UI.Catalog, Culture=Neutral, Version=1.0.0.0, PublicKeyToken=31bf3856ad364e35">
<ConfigSettings>
<ConfigSetting Name="NextButtonText">>></ConfigSetting>
<ConfigSetting Name="PreviousButtonText"><<</ConfigSetting>
<ConfigSetting Name="CssClassPageSelected">mscs-pageSelected</ConfigSetting>
</ConfigSettings>
</XsltAction>
<br/>
<xsl:choose>
<xsl:when test="count(product) = 0">
<p>No products were found.</p>
</xsl:when>
<xsl:otherwise>
<div class="mscs-column100">
<table>
<xsl:apply-templates select="product/properties[position()mod 2=1]"/>
</table>
</div>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
<xsl:template match="properties">
<xsl:variable name="imgURLBase" select="property[@name='Image_filename']"/>
<xsl:variable name="productID" select="property[@name='Id']"/>
<xsl:variable name="listPrice" select="property[@name='ListPrice']"/>
<xsl:variable name="alt" select="property[@name='Description']"/>
<xsl:variable name="onSale" select="property[@name='OnSale']"/>
<xsl:variable name="catalog" select="$_catalog"/>
<xsl:variable name="categoryId" select="$_category"/>
<xsl:variable name="imagesPath" select="$DefaultImagesRepository"/>
<tr>
<!-- dictate whether this is an odd or even row -->
<xsl:attribute name="class">
<xsl:choose>
<xsl:when test="position()mod 2">odd</xsl:when>
<xsl:otherwise>even</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<!-- these table cells contain the data for 'odd' numbered rows -->
<td>
<div class="mscs-column20">
<xsl:choose>
<xsl:when test="$imgURLBase = ''">
<b>No Image Available</b>
</xsl:when>
<xsl:when test="$imgURLBase != ''">
<a href="/Pages/Product.aspx?category={$categoryId}&cat={$catalog}&id={$productID}">
<img src="{$imagesPath}/{$imgURLBase}" class="mscs-ProductImage" border="0" alt="{$alt}"/>
</a>
</xsl:when>
</xsl:choose>
</div>
<div class="mscs-column80">
<div>
<div class="mscs-ProductName">
<a href="/Pages/Product.aspx?category={$categoryId}&cat={$catalog}&id={$productID}">
<xsl:value-of select="property[@name='DisplayName']"/>
</a>
</div>
<div class="mscs-ProductPrice"> Price: <xsl:value-of select="format-number($listPrice, "$#0.00")"/>
</div>
</div>
<div style="width: 100%;">
<span class="mscs-clear"/>
</div>
<div class="mscs-ProductDescription">
<xsl:value-of select="property[@name='Description']"/>
</div>
<div>
<XsltAction Id="AddToCart" Type="Microsoft.Commerce.Portal.UI.Catalog.WebControls.VariantAddToCartXsltAction, Microsoft.Commerce.Portal.UI.Catalog, Culture=Neutral, Version=1.0.0.0, PublicKeyToken=31bf3856ad364e35">
<ConfigSettings>
<ConfigSetting Name="ProductId">
<xsl:value-of select="property[@name='Id']"/>
</ConfigSetting>
<ConfigSetting Name="DisplayAddToShopperList">true</ConfigSetting>
<ConfigSetting Name="AddToShopperListDefault">false</ConfigSetting>
<ConfigSetting Name="ImageButtonUrl"/>
</ConfigSettings>
</XsltAction>
</div>
</div>
</td>
<!-- these table cells contain the data for 'even' numbered rows -->
<xsl:choose>
<!-- look for a sibling with same name as current node -->
<xsl:when test="count(following-sibling::*[name()=name(current())])">
<td>
<div class="mscs-column20">
<xsl:choose>
<xsl:when test="$imgURLBase = ''">
<b>No Image Available</b>
</xsl:when>
<xsl:when test="$imgURLBase != ''">
<a href="/Pages/Product.aspx?category={$categoryId}&cat={$catalog}&id={$productID}">
<img src="{$imagesPath}/{$imgURLBase}" class="mscs-ProductImage" border="0" alt="{$alt}"/>
</a>
</xsl:when>
</xsl:choose>
</div>
<div class="mscs-column80">
<div>
<div class="mscs-ProductName">
<a href="/Pages/Product.aspx?category={$categoryId}&cat={$catalog}&id={$productID}">
<xsl:value-of select="property[@name='DisplayName']"/>
</a>
</div>
<div class="mscs-ProductPrice"> Price: <xsl:value-of select="format-number($listPrice, "$#0.00")"/>
</div>
</div>
<div style="width: 100%;">
<span class="mscs-clear"/>
</div>
<div class="mscs-ProductDescription">
<xsl:value-of select="property[@name='Description']"/>
</div>
<div>
<XsltAction Id="AddToCart" Type="Microsoft.Commerce.Portal.UI.Catalog.WebControls.VariantAddToCartXsltAction, Microsoft.Commerce.Portal.UI.Catalog, Culture=Neutral, Version=1.0.0.0, PublicKeyToken=31bf3856ad364e35">
<ConfigSettings>
<ConfigSetting Name="ProductId">
<xsl:value-of select="property[@name='Id']"/>
</ConfigSetting>
<ConfigSetting Name="DisplayAddToShopperList">true</ConfigSetting>
<ConfigSetting Name="AddToShopperListDefault">false</ConfigSetting>
<ConfigSetting Name="ImageButtonUrl"/>
</ConfigSettings>
</XsltAction>
</div>
</div>
</td>
</xsl:when>
</xsl:choose>
</tr>
</xsl:template>
</xsl:stylesheet>
Once you are happy with this, simply paste the text back in and hit OK on the window. If you do not wish to overwrite the existing style sheets – make sure you enter in a new filename before you hit the save button. Then simply click the Save to Document Library button, and press OK to close the menu on the right of the screen. When the page refreshes you should see you the outcome immediately on your web part. Once you are done simply publish your page for your changes to go live.
The biggest benefit here is these changes are restricted to a single page in your site, but by saving you style sheet back to the document library you can re-use your template in different site pages in the same web parts, or alternately have different templates for different catalogues within your site, the choice on styling is yours!
One thing to note here is Commerce Server 2009 through SharePoint utilise XSL heavily in customisation of its User Interface, so I would strongly recommend that if you want to deploy sites using SharePoint as a CMS that you learn some basics around XSL and get yourself a good editor which can validate your XSL before you save it back into your web part dialogues. Unfortunately SharePoint does not validate XSL and will through errors or exceptions which sometimes you will not understand, simply because invalid XSL has been used, so my best tip is to validate your code before putting it into SharePoint interfaces!
If you have particular questions on Commerce Server customisation, or generally please feel free to contact me direct or ask away on the MSDN forums... !
After its recent Australian successes in Sydney and Adelaide SharePoint Saturday is back, and this time it debuts in Melbourne. The follow up to its premier events takes place on November 14th and is set in Clifton's, 440 Collins St, Melbourne CBD. Currently speakers are to be announced, but I have submitted an application to run a session on Commerce Server and SharePoint, so if you are interested in SharePoint based e-Commerce, and want to touch-base feel free to catch me at this event.
As ever keep an eye on the SharePoint Saturday event website: http://www.sharepointsaturday.org/melbourne/default.aspx or follow the #SPSMelbourne hashtag on Twitter.
I look forward to seeing you all at the event!
For many customers the ROI on software licences is one of the key factors when purchasing software, so when deploying an e-Commerce solution the level of return for frameworks, and CMS platforms such as Commerce Server and MOSS are quite justifiable, however it is the extra features – such as the Store Locator that is difficult spending licensing money on. The current store locator within CS 2009 is based on a commercial Microsoft Virtual Earth web-service, which is provided for non-developer used at extra cost above your Commerce Server licensing. Although I have no problems with the VE licensing model when deploying GIS and Geographical based application, it is a difficult cost to justify when all you want to do is a simply app like a store locator.
A requirement of one of my recent projects however was to deploy a store locator-style application without the extra licensing cost but still using Commerce Server profile objects so a custom can be associated back to a specific store location profile. So here's how I went about doing so:
Firstly I extended the existing Store Profile object which comes out-of-the-box in the standard Commerce Server 2009 install and added some extra attributes. The key attributes here are longitude, and latitude – the exact geographical location of that store. For the purposes of this tutorial I have assigned them to the store object, however technically these are properties of an address profile and not the store itself.
These properties are mapped to two columns added as an extension of the StoreObject table, both being nullable floats.
Now you have somewhere to keep the geographical location of your stores, how do you get the values? Well the answer is more where. For simplicities sakes you can batch "Geocode" [the process of plotting your stores on a map to find the latitude and longitude co-ordinated], and upload the data when you initially upload your stores. For my example I simply had a list of addresses in a CSV file and used a Google Maps Geocodes (http://mapsapi.googlepages.com/batchgeo.htm). Alternately both Google (http://code.google.com/apis/maps/documentation/services.html) and Bing (http://msdn.microsoft.com/en-us/library/cc966793.aspx) offer free XML web service based API's which allow you to geocode in real time. These are easy to implement and well documented – so this is the route I would strongly recommend.
Having a list of stores in a database, with geographical co-ordinates accessible via the Commerce Server profile system is all well and good, however it provides no end-user benefit. So to implement a functionality we want to deploy we head back to our SQL database. A few years ago, when we discovered the world was actually a sphere, it didn't take much longer for mathematicians to formulate distances using the universal grid system we have just discovered – latitude and longitude. So it is possible using relatively straightforward geometry to calculate the distance in Kilometres objects are from a known location, so in our example calculate the distance our stores are from the uses given address. To do this dynamically we are going to write a SQL function, which will return a temporary table containing the id of our stores, and the distance from our known location. The function looks something similar to this:
Create
FUNCTION [dbo].[fnNearestStoreByCoord]
(
@lat AS
float,
@long AS
float
)
RETURNS @stores TABLE (idStore INT, storeName varchar(100), km FLOAT)
AS
BEGIN
IF
NOT
(@lat IS
NULL
OR @long IS
NULL) BEGIN
-- Find the nearest store
INSERT
INTO @stores
SELECT
dbo.StoreObject.u_store_id,
dbo.StoreObject.u_store_name,
6378.7 *
acos(sin(RADIANS(u_latitude))
* sin(RADIANS(@lat))
+ cos(RADIANS(u_latitude))
* cos(RADIANS(@lat))
* cos(RADIANS(@long)
- RADIANS(u_longitude)))
AS km
FROM
StoreObject
ORDER
BY
km
END
RETURN
END
You will notice that we pass in two parameters – which are our known longitude and latitude and we get a return of our store ID, name, and the distance from our provided location in kilometres. We can know call this query direct and get an accurate response – however for the sake of best practice lets implement a store procedure that can do a bit of house keeping for us:
ALTER
PROCEDURE [dbo].[FindNearestStore]
(
@lat float,
@long float
)
AS
SELECT
Top 4
idStore,
storeName,
km
FROM
fnNearestStoreByCoord(@lat, @long)
ORDER
BY
km
As you can see our stored procedure is calling our function, as you would a normal SQL table and passing its required parameters. However in this instance we are limiting the amount of rows being returned to 5, and ordering by the closest – so we don't inundate our end user with stores that are no longer close to them.
So now we have our store locator logic in-place. It is in the data layer, so it is fast and tied in to our Commerce Server profile which is what we wanted – but at the moment we cannot access it via our managed .NET code.
So know we hit the Commerce Server API to try and get access to newly developed database functionality – so we can deploy it to our site. The new Commerce Server API allows us to have a standard interface through entities to all of our Commerce Server objects. So first thing we need to do is extend the Store Profile entity, and its ORM with the MetadataDefintions.xml file.
If you have done this correctly you should end up with extra code lines similar to this within your StoreProfile class:
///
<summary>
/// The geocoded latitude value
///
</summary>
public
decimal Latitude
{
get
{
return
Convert.ToDecimal(this._commerceEntity.GetPropertyValue(PropertyName.Latitude));
}
set
{
this._commerceEntity.SetPropertyValue(PropertyName.Latitude, value);
}
}
///
<summary>
/// The geocoded longitude value
///
</summary>
public
decimal Longitude
{
get
{
return
Convert.ToDecimal(this._commerceEntity.GetPropertyValue(PropertyName.Longitude));
}
set
{
this._commerceEntity.SetPropertyValue(PropertyName.Longitude, value);
}
}
And in you MetadataDefinitions.xml file;
<PropertyMappings>
<PropertyMapping
property="Id"
csProperty="GeneralInfo.store_id" />
<PropertyMapping
property="DateCreated" csProperty="ProfileSystem.date_created" />
<PropertyMapping
property="DateModified" csProperty="ProfileSystem.date_last_changed" />
<PropertyMapping
property="ModifiedBy" csProperty="ProfileSystem.store_id_changed_by" />
<PropertyMapping
property="Name" csProperty="GeneralInfo.store_name" />
<PropertyMapping
property="Latitude" csProperty="GeneralInfo.store_latitude" />
<PropertyMapping
property="Longitude" csProperty="GeneralInfo.store_longitude" />
</PropertyMappings>
Now we have access to the properties we created in step 1, but as of yet not the stored procedure. To call our SQL functionality we need to implement another new concept for Commerce Server 2009 – a sequential component. To assist with backwards compatibility and extensibility the new Commerce Server API is simply an abstracted layer mapped back to the existing framework from Commerce Server 2007. When you call a commerce entity you object originates from the 2007 context, and is passed through a sequence of Commerce Server components that implements, validates and then casts the legacy object into the new standardised API. These layers provide an extensible place to inject extra levels of validation, and access to external systems. So this is where we will access our new store procedure.
So the first step is to create a new class which extends the ProfileLoaderBase class. This abstract class is responsible for loading all profile data from the 2007 context objects. Typically if you tried to call a StoreObject, you request would be routed to the StoreProfileLoader class which limits you to only returning an object by one its primary keys. This is due to the limitation of the underlying 2007 profile context, so to extend this limitation we need to override the default ExecuteQuery method. So we are going to replace it with something that looks like this:
public
override
void ExecuteQuery(CommerceQueryOperation queryOperation, Microsoft.Commerce.Broker.OperationCacheDictionary operationCache, CommerceQueryOperationResponse response)
{
int? count;
List<Profile> matches = new
List<Profile>();
ParameterChecker.CheckForNull(queryOperation, "queryOperation");
ParameterChecker.CheckForNull(operationCache, "operationCache");
ParameterChecker.CheckForNull(response, "response");
CommerceModelSearch searchCriteria = queryOperation.SearchCriteria as
CommerceModelSearch;
if (searchCriteria.Model.Properties["Latitude"] == null && searchCriteria.Model.Properties["Longitude"] == null)
{
matches = base.GetMatches(searchCriteria,out count);
}
else
matches = GetClosestStores((decimal)searchCriteria.Model.Properties["Latitude"], (decimal)searchCriteria.Model.Properties["Longitude"], out count);
operationCache.SetProfileOperationTargets(base.ProfileEntityMappings.CommerceServerDefinitionName, matches);
operationCache.SetProfileTargetsTotalItemCount(base.ProfileEntityMappings.CommerceServerDefinitionName, count);
}
If you have used the 2009 SDK (which I hope you would have if you have managed to follow me this far) then you will now that when you create a Commerce Query object you define which properties of that particular model you wish to search on. The code we have implemented is 95% the original ExecuteQuery method from the base class, except we want to intercept the method before it hits the GetMatches call. This the GetMatches method is simply calling the ProfileContext and returning a profile based on its ID. Instead we want to be able to call our own method if we have provided the longitude and latitude parameters, and if we haven't – well then simply allows the class to call its method as normal.
Our method GetClosestStores is even simpler still – all we are going to do is call the stored procedure, return the list of closest ID's and then grab those profiles out of the database. The only difficult part is because the Profile system is not necessarily SQL based you can't call a connection string directly – instead you have to go through the legacy OLEDB components to access the underlying data stores. So our GetClosestStores method will end up looking something like this :
private
List<Profile> GetClosestStores(decimal lati, decimal longi, out
int? totalCount)
{
List<Profile> matches = new
List<Profile>();
int i = 0;
try
{
CommerceResourceCollection rscol = new
CommerceResourceCollection(CommerceContext.Current.SiteName);
string bizDataConnStr = rscol["Biz Data Service"]["s_BizDataStoreConnectionString"].ToString();
OleDbConnection conn = new
OleDbConnection(bizDataConnStr);
List<int> profiles = new
List<int>();
conn.Open();
try
{
OleDbCommand command = new
OleDbCommand("FindNearestStore", conn);
OleDbParameter latitude = command.Parameters.Add("@lat", OleDbType.Decimal);
latitude.Direction = ParameterDirection.Input;
OleDbParameter longitude = command.Parameters.Add("@long", OleDbType.Decimal);
longitude.Direction = ParameterDirection.Input;
latitude.Value = lati;
longitude.Value = longi;
command.CommandType = CommandType.StoredProcedure;
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
profiles.Add((int)reader[0]);
i++;
}
reader.Close();
command.Dispose();
}
catch(Exception ex) { }
finally
{
conn.Close();
}
foreach (var p in profiles)
{
ProfileContext context = CommerceSiteContexts.Profile[OperationContext.CurrentInstance.SiteName];
matches.Add(context.GetProfile(p, base.ProfileEntityMappings.CommerceServerDefinitionName));
}
}
catch (Exception ex) { }
totalCount = i;
return matches;
}
As you can see – it's pretty straight forward, with the logic simply retrieving a list of ids from the database stored procedure call (using our known longitude, and latitude) and then looping through those ID's to retrieve a list of profile objects. That's the only modifications we need to make. The underlying profile base classes have been designed to accept a collection of profiles, and will return them as strongly typed commerce entities when requested. So now we have our sequence component we need to get Commerce Server to use ours instead of the default one. We done this by editing the ChannelConfiguration.config file. This file defines the sequential components for the whole site (channel) so we simply need to find the default StoreProfileLoader component and replace it with what we have just created, which looks something like this:
<!--<Component name="Store Profile Loader" type="Microsoft.Commerce.Providers.Components.StoreProfileLoader, Microsoft.Commerce.Providers, Version=1.0.0.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35"/>-->
<Component
name="Store Profile Loader"
type="Sample.Web.Logic.Components.StoreProfileSequenceComponent, Sample.Web.Logic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=sampleKey"/>
That's it – we are up and ready, and can now make a query. Following the same convention as the 2009 SDK we can simply deploy this method in a static controller class, in a manner similar to this:
public
static
List<StoreProfile> GetStoresByLongLat(decimal latitude, decimal longitude )
{
List<StoreProfile> stores = new
List<StoreProfile>();
CommerceQueryRelatedItem<Address> address = new
CommerceQueryRelatedItem<Address>(StoreProfile.RelationshipName.Addresses);
CommerceQuery<StoreProfile> storeQuery = new
CommerceQuery<StoreProfile>();
storeQuery.SearchCriteria.Model.Latitude = latitude;
storeQuery.SearchCriteria.Model.Longitude = longitude;
storeQuery.RelatedOperations.Add(address);
CommerceResponse response = SiteContext.ProcessRequest(storeQuery.ToRequest());
CommerceQueryOperationResponse queryResponse = response.OperationResponses[0] as
CommerceQueryOperationResponse;
foreach (var store in queryResponse.CommerceEntities)
{
stores.Add(new
StoreProfile(store));
}
return stores;
}
and then we can implement this on our front end in an ASP.NET AJAX enabled web service:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
[PresenterHost(typeof(StoreLocatorPresenter), typeof(IStoreLocatorView))]
public
class
StoreLocator : WebServiceBase<StoreLocatorModel>, IStoreLocatorView
{
[WebMethod]
public
List<StoreProfile> FindNearestStoreByLongLat(decimal longitude, decimal latitude)
{
return GetStoresByLongLat(longitude, latitude);
}
And there you have it – a web service, exactly the same as the Virtual Earth FindMyNearest service built in-house at no extra cost. You can now use either Google or Bing maps, to Geocode your customers locations, post the longitude and latitude to your local services, and plot the response on a map. Using a library such as JQuery – this is possible in about 15 lines of code. Your end result – something flexible to deploy, easy to use, and you get a better understanding of the Commerce Server 2009 SDK.
As per my last post I am setting up a sample ASP.NET solution – so once I have finished work on that, I will endeavour to package up my source code and some sample JavaScript and link to it of my blog. So stay tuned for updates – but in the meantime if you have questions please feel free to ask!
NB: This is my first technical tutorial.. so constructive criticism is welcome!
Commerce Server 2009 was the single biggest upgrade to the Microsoft e-commerce platform in nearly 10 years. A large proportion of the changes are the introduction of a single API covering the multiple business logic implementations required within an e-Commerce site. In former releases business concepts such as inventory, catalogue, order management, user profiling, and marketing had each been separated into their own domain logic and thus each had a unique API which made it difficult for new developers to adopt the concepts. As I mentioned in previous posts the new API unifies the previous implementations into single interface known as Multi-Channel Commerce Foundation.
These changes have been technically documented on MSDN; however there is currently a lack of community based documentation available on the Internet to support new developers, and existing Commerce Server developer migrating across to the new-style platform. Having spent a lot of time on the MSDN forums in the past months it also seems to be clear that a big misconception is the new API has been tailored towards implementation exclusively onto a SharePoint CMS website. Although the marketing does indicate SharePoint is the best platform in which to deploy a Commerce Server site (and being a SharePoint developer I do agree that there is a good case), it is not however the only solution. There is a multi-channel foundation SDK which demonstrates basic examples using ASP.net web forms, however unlike previous releases there is not a full sample solution deployed on ASP.NET.
So not to discount the non-SharePoint developers from understanding the benefits of using Commerce Server, and the simplicity and flexibility of the new API, I have set up an Open-Source ASP.NET based sample site on CodePlex. Over the next few days I will gradually be uploading the solution which is directly ported across from the Commerce Server 2009 starter site designed for SharePoint. The solution itself will be developing primarily using ASP.NET web-forms with an MVP design pattern implantation, and secondly will also be implanted into an ASP.NET MVC solution too.
The URL for the CodePlex site http://cs2009aspnet.codeplex.com so if you are keen to see a sample solution using Commerce Server 2009 and ASP.NET feel free to download the source code, or alternately if you wait a couple of days you should have an out-of-the-box solution to deploy directly onto your server. This blog, and the wiki on the CodePlex (until I get around to building my personal web-site) will also serve as a source of community orientated tutorials and documentation area to help people get up and running faster when using Commerce Server.
So if you are new to the platform, or want to get a heads up on how to get up and running please check out the CodePlex solution, or if you have particular questions or have comments and suggestions, please feel free to get in touch via my blog.
NB: In a previous post I talked about a tutorial series on implanting a Commerce Server solution. This has been delayed slightly by me moving house, and Australian ISP's taking several weeks to organise an internet connection. I will try and get these posts online ASAP.
OK so the title may confuse you – two completely different technologies that are hardly related. However I have been a little busy at nights trying to prepare my Music-Works tutorials for Commerce Server/SharePoint (MOSS) so I thought I would provide an update into something interesting I was playing with
yesterday.
For those of you who may not know Microsoft Tag is Microsoft's implementation of the QR-Code. Tags are used in marketing for providing online content in off-line medium. The tags themselves are essentially 2-dimensional barcodes which are read by a plug-in to a mobile smart device (such as an IPhone, WinMo, or Palm), the software is installed by default for a few carriers in the US, or otherwise is available as a very small download direct to the handset. The benefit of the tag to the business is the provision of something similar to click-tracking for off-line media, the guise is that people will read an advert in say a newspaper or billboard and instead of writing down a URL they simply can snap the code and the mobile device either stores, or pushes you to content about that product. Once the tag has been read the business user then is provided with a detailed report on the usage of that specific tag, which provides marketers with an understanding of the uptake of the off-line adverts.
Because the plug-in if not a standard feature of most mobile handsets, you consumers are provided with some incentives for tagging content, such as during the release of Halo 3 if users tagged the promotional posters in stores they received exclusive video content prior to main stream release.
You may be wondering why and how this relates to Commerce Server though? Well one of the primary features on Commerce Server is the reporting of e-Commerce activity online, but with the recent popularity in multi-channel how can an online retail experience augment into the real world? Well as a starting point you could use tags. Tagging content is easy, simply sign up on the beta website provide a URL, or action for the tag and the site will automatically generate a print quality tag to feature to be included in your artwork. So to links this back to Commerce Server, simply setup a campaign in your marketing manager, and provide all the necessary details are you would a traditional add. Commerce Server will then generate a URL used for tracking purposes related to that ad, use this URL as a tag action and you have managed to link the two together.
Yes it sounds easy, but tagging can be taken one step further to possibly introduce social networking into your traditional retail space. A good example would be tagging all books in a book store, and using the custom app people can be browsing in-store, tag the book and immediately info from your e-Commerce site such as user reviews, rich media, and cross-sales are sent directly to the that users phone. This intern provides a completely integrated multi-channel solution that crosses e-Comm and traditional retail boundaries.
My beliefs are tags will eventually grow in western communities, following on from their success in Japan, and with the growth of smart mobile devices. The question is will they simply end up as a bloated advertising solution, or are they the first step to providing a cross-channel social retail experience? The choice is really up to the technologists on how to implement them!
Yesterday in New Orleans, the Microsoft World Partner Conference 2009 kicked off with some of the big highlights at the event where the Office 2010, and Office web-apps announcements, with SharePoint appearing high on the list. The event has also kicked off a few sneak-peaks into the new platform, scheduled for an exclusive-beta program in the coming weeks.
While I digest the amount of data being released, here is a quick glance at some of the new SharePoint 2010 screens...
New User Interface, which now includes the Office Ribbon Menu:
Web edit interface, with similar structure to Microsoft Word (also note that this is being demoed in Firefox too!);
Use of rich media such as Silverlight in web parts:
Richer theming controls for out-of-the-box layouts and templates: