Welcome to MSDN Blogs Sign in | Join | Help

Cristiano WebLog

Microsoft Infrastructure & Development Tips and Tricks
Exporting and Importing CS2007 Marketing Data

Are you looking for a way to import and/or export Commerce Server 2007 Marketing data?

The following code samples show how to to export and import all CS2007 Marketing System data. The first sample uses the MarketingPup.Export method to extract the data and create a XML file with all content.

   1: using System;
   2: using System.IO;
   3: using Microsoft.CommerceServer.Internal.Marketing;
   4: using Microsoft.CommerceServer.Runtime.Configuration;
   5:  
   6: namespace ExportMarketingData
   7: {
   8:     class ExportMarketingData
   9:     {
  10:         static void Main(string[] args)
  11:         {
  12:             if (args.Length != 2)
  13:             {
  14:                 Console.WriteLine("Exports a Microsoft Commerce Server site's Marketing resource to a file.");
  15:                 Console.WriteLine("ExportMarketingData.exe [sitename] [export directory]");
  16:                 return;
  17:             }
  18:  
  19:             // let Pup validate the site so we get a descriptive error if something is wrong
  20:             string sitename = args[0];
  21:  
  22:             // validate export directory exists
  23:             string exportDirectory = args[1];
  24:             DirectoryInfo dirInfo = new DirectoryInfo(exportDirectory);
  25:             if (!dirInfo.Exists)
  26:             {
  27:                 Console.WriteLine("The specified output directory {0} does not exist", exportDirectory);
  28:                 return;
  29:             }
  30:  
  31:             // validate export file does not exist
  32:             FileInfo fileInfo = new FileInfo(Path.Combine(exportDirectory, "MarketingData.xml"));
  33:             if (fileInfo.Exists)
  34:             {
  35:                 Console.WriteLine("Cannot overwrite existing file {0}", fileInfo.FullName);
  36:                 return;
  37:             }
  38:  
  39:             // do the export
  40:             MarketingPup pup = new MarketingPup();
  41:             pup.Export(sitename, "Marketing", exportDirectory, 0, 0);
  42:  
  43:             // print success 
  44:             Console.WriteLine("Exported file {0}", fileInfo.FullName);
  45:         }
  46:     }
  47: }

The second sample uses the MarketingPup.Import method to import the marketing data from a XML file.

   1: using System;
   2: using System.IO;
   3: using Microsoft.CommerceServer.Internal.Marketing;
   4: using Microsoft.CommerceServer.Runtime.Configuration;
   5:  
   6: namespace ImportMarketingData
   7: {
   8:     class ImportMarketingData
   9:     {
  10:         static void Main(string[] args)
  11:         {
  12:             if (args.Length != 2)
  13:             {
  14:                 Console.WriteLine("Imports a Microsoft Commerce Server site's Marketing resource file.");
  15:                 Console.WriteLine("ImportMarketingData.exe [sitename] [import directory]");
  16:                 return;
  17:             }
  18:  
  19:             // let Pup validates the site so we get a descriptive error if something is wrong
  20:             string sitename = args[0];
  21:             
  22:             string importDirectory = args[1];
  23:  
  24:             DirectoryInfo dirInfo = new DirectoryInfo(importDirectory);
  25:             if (!dirInfo.Exists)
  26:             {
  27:                 Console.WriteLine("The specified input directory {0} does not exist", importDirectory);
  28:                 return;
  29:             }
  30:  
  31:             // do the import
  32:             MarketingPup pup = new MarketingPup();
  33:             pup.Import(sitename, "Marketing", importDirectory, 0);
  34:  
  35:             // print success 
  36:             Console.WriteLine("Imported file {0}", dirInfo.FullName);
  37:         }
  38:     }
  39: }

The code samples described here can be used to create console tools or event processing components to do bulk exports and imports to/from the CS2007 Marketing System.

I've also attached a Visual Studio solution containing two console tools to export/import marketing data.

Regards, Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Product Relationship Names: Easier for Business Users

If you are following my posts you probably have noticed the one showing how to create bundles for Commerce Server 2007. Bundles are created using product relationships with a specific name.

Some of my customers believe it is too complicated for business users to create relationships with a particular name in order to create bundles. So they asked to make a small change on the Catalog Manager to create combo boxes with enumeration options on the relationship name column of the product relationships tab (product detail).

The aim is to do something similar to the dialog below:

image

In order to change the free text box by a combo box on the relationship name during the creation of new product relationships the you need to change the code of the Commerce Server 2007 Catalog Manager.

The source code is available on the Partner SDK under the Applications\CatalogManager folder.

The datagrid for the Product Relationships is created by the CreateDatagrid function inside the CatalogItemRelationships.cs file.

The datagrid used to show the relationships is derived from the default DatagridView control and it is named ColumnBasedDatagrid. It is defined on the ColumnBasedDatagrid.cs file inside the UI control collection source code.

The display method of the ColumnBasedDatagrid named dataGridViewRelationships has a parameter PropertyStore. A Propertystore is a collection of PropertyInfo objects. Based on the type passed as the third parameters of each PropertyInfo object inside this collection, the datagrid columns are created to show the relationships.

The default PropertyInfo supports the Datatype.String and Datatype.Enumeration types. The default type used for the RelationshipName is Datatype.String. If the developer changes the datatype used to Datatype.Enumeration, the datagrid will be created with a combo-box instead a plain text box as expected.

Custom code is also necessary to deal with the enumeration definition. The enumeration that will be shown in the screen must be defined in a database or even inside the code. The following code was used to fill the enumeration with sample possible values: AWARD, GROUPRELATION, BUNDLECOMPONENT, COMPOSITECHILD, and CROSSSELL. It was included inside the CreateDataGrid function.

The code below shows the CreateDatagrid function already changed to use the combo box instead the regular text box.

   1: private void CreateDataGrid()
   2: {
   3:     if (this.dataGridViewRelationships.ColumnCount == 0)
   4:     {
   5:         PropertyStore propertyStore = new PropertyStore();
   6:  
   7:         StringCollection values = new StringCollection();
   8:         values.add (“AWARD”);
   9:         values.add (“GROUPRELATION”);
  10:         values.add (“BUNDLECOMPONENT”);
  11:         values.add (“COMPOSITECHILD”);
  12:         values.add (“CROSSSELL”);
  13:  
  14:         PropertyInfo propertyInfo = new PropertyInfo(true, true, DataType.Enumeration, values, “Name”, CatalogResourceFile.COLUMN_RELATIONSHIP_NAME, UIHelpers.relationship);
  15:         propertyInfo.ColumnDisplayWidth = 120;
  16:         propertyStore.Add(propertyInfo);
  17:         propertyInfo = new PropertyInfo(true, false, DataType.String, 1, 128, CatalogResourceFile.COLUMN_ITEM_NAME, UIHelpers.item, null);
  18:         propertyInfo.ColumnDisplayWidth = 120;
  19:         propertyStore.Add(propertyInfo);
  20:         propertyInfo = new PropertyInfo(true, false, DataType.String, 1, 128, CatalogResourceFile.COLUMN_ITEM_NAME, "ItemName", null);
  21:         propertyInfo.ColumnDisplayWidth = 120;
  22:         propertyStore.Add(propertyInfo);
  23:         propertyInfo = new PropertyInfo(true, false, DataType.String, 1, 128, CatalogResourceFile.COLUMN_CATALOG_NAME, UIHelpers.catalog, null);
  24:         propertyInfo.ColumnDisplayWidth = 120;
  25:         propertyStore.Add(propertyInfo);
  26:         propertyInfo = new PropertyInfo(true, false, DataType.String, 1, 128, CatalogResourceFile.COLUMN_CATALOG_NAME, "CatalogName", null);
  27:         propertyInfo.ColumnDisplayWidth = 120;
  28:         propertyStore.Add(propertyInfo);
  29:         propertyInfo = new PropertyInfo(false, false, DataType.String, 1, 128, CatalogResourceFile.COLUMN_ITEM_TYPE_NAME, UIHelpers.itemType, null);
  30:         propertyInfo.ColumnDisplayWidth = 120;
  31:         propertyStore.Add(propertyInfo);
  32:         propertyInfo = new PropertyInfo(false, true, DataType.String, 1, 128, CatalogResourceFile.COLUMN_DESCRIPTION_NAME, UIHelpers.relationshipDescription, null);
  33:         propertyInfo.ColumnDisplayWidth = 120;
  34:         propertyStore.Add(propertyInfo);
  35:         propertyInfo = new PropertyInfo(false, true, DataType.String, 1, 128, "OldRelationshipName", "OldRelationshipName", null);
  36:         propertyInfo.ColumnDisplayWidth = 120;
  37:         propertyStore.Add(propertyInfo);
  38:         propertyInfo = new PropertyInfo(true, true, DataType.Integer, null, null, SequenceColumn, SequenceColumn, null);
  39:         propertyInfo.ColumnDisplayWidth = 20;
  40:         propertyStore.Add(propertyInfo);
  41:         dataGridViewRelationships.Display(propertyStore, null);
  42:         dataGridViewRelationships.Columns["CatalogName"].Visible = false;
  43:         dataGridViewRelationships.Columns["ItemName"].Visible = false;
  44:         dataGridViewRelationships.Columns["OldRelationshipName"].Visible = false;
  45:         dataGridViewRelationships.Columns[SequenceColumn].Visible = false;
  46:         dataGridViewRelationships.Columns[SequenceColumn].SortMode = DataGridViewColumnSortMode.Automatic;
  47:         StringCollection uniqueColumns = new StringCollection();
  48:         uniqueColumns.Add(UIHelpers.relationship);
  49:         uniqueColumns.Add("ItemName");
  50:         uniqueColumns.Add("CatalogName");
  51:         uniqueColumns.Add(UIHelpers.itemType);
  52:         this.dataGridViewRelationships.SetUniqueCoulmns(uniqueColumns);
  53:     }
  54: }

Regards, Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Unit testing and Commerce Server 2007 Contexts

Hi there... after a long time, I'm back.

Let's talk a little about unit testing and commerce server... I've been helping one of our parters with a CS2007 website development and they were facing problems with unit testing and commerce server contexts created by the httpmodules.

As you probably know, test driven development and unit testing require a lot from the architecture. In order to do effective unit tests, the system need to be divided in units and those units need to be tested under a set of conditions that, ideally, allow near total code coverage.

The problem with unit testing and Commerce Server 2007 is that the Microsoft’s e-commerce framework is heavily reliant on HTTP modules to initialize some special contexts. For example, the CommerceContext (which is created by one web.config specified HTTP module) provides access to various subsystems needed for catalog, profiles and orders operations.

This tightly coupled HTTP dependency makes hard to deal with conventional out-of-process unit tests and Commerce Server 2007 applications running inside IIS and using http modules to create contexts.

The tricks is create a unit test configuration file and attaching the unit test manager process to the IIS, this procedure makes possible the access to all contexts created by Commerce Server 2007 HTTP modules.

This configuration can be done following the steps below:

1. Open Visual Studio .Net 2005. Right-click on the Solution Items folder and select Add, New Item…

image

2. On the “Add New Item” page, select “Test Run Configuration” and click Add.

image

3. Select Hosts, and change the “Host Type” to ASP.Net. In the “URL to test” text box, type the URL of your website and select “Run tests in IIS”. Click Apply and Close.

image

4. Ensure that the configuration that you just done is being used as the Active Test Run Configuration.

image

5. Now run the Unit Test. All unit tests which have dependency to CommerceContext will run.

As an additional note is the recommendation to run at least Visual Studio 2005 Service Pack 1. That is because StarterSite comes with some Unit Tests but the configuration file available together with the tests doesn’t work without the SP1 installed.

See you soon!

Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Programming Display Windows - Static Version [Part II]

If you followed the last post you now have a brand new DisplayTemplate on the marketing system with three properties: ProductImage, ProductTitle and ProductPrice.

Before creating new advertisements and associate the new DisplayTemplate we will need an expression. This expression will be used to filter only advertisements for a determined display window.

To do that, we need two steps:

  1. Create a new targeting context attribute called BillBoard using the Commerce Server Manager.
  2. Create a new global expression to be used on the Target Expressions of the advertisements that we will create on the next post. :)

Step 1

  • Open the Commerce Server Manager and navigate to Commerce Server Manager/Global Resources/Profiles(<Your Server>_StarterSite_Profiles)/Profile Catalog/Profile Definitions/Targeting Context
  • On the right side of the window, click Add.
  • Select Add New Property and click OK.

image 

  • Fill the boxes Name and DisplayName with BillBoard.
  • Very important!!! Click Apply and on the small diskette icon on the top of the Commerce Server Manager.
  • Your profile definition will be like the following picture:

image

Step 2

Great. Now we have a new TargetingContext property. It's time to create a new global expression. This expression will be associated to the advertisement and will be used during the  content selection to filter only advertisements fitting to our display window.

The following code can be used on a Console Application to create the appropriate global expression:

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.CommerceServer;
using Microsoft.CommerceServer.Marketing;
using System.Xml;

namespace CreateGlobalExpression
{
    class Program
    {
        static void Main(string[] args)
        {
            // Set the URL to the Web service.
            string marketingWebServiceUrl = @"
http://localhost/MarketingWebService/MarketingWebService.asmx";
            // Create an instance of the Marketing System agent.
            MarketingServiceAgent ma = new MarketingServiceAgent(marketingWebServiceUrl);
            MarketingContext marketingSystem = MarketingContext.Create(ma);

            //Creating the global expression
            XmlDocument xmlDoc = new XmlDocument();
            XmlElement clause = xmlDoc.CreateElement("CLAUSE");
            clause.SetAttribute("OPER", "equal");

            XmlElement property = xmlDoc.CreateElement("PROPERTY");
            property.SetAttribute("ID", "TargetingContext.BillBoard");
            property.SetAttribute("TYPE", "STRING");

            XmlElement immedval = xmlDoc.CreateElement("IMMED-VAL");
            immedval.SetAttribute("TYPE", "STRING");

            XmlElement value = xmlDoc.CreateElement("VALUE");
            value.InnerText = "MainDisplayWindow";

            immedval.AppendChild(value);
            clause.AppendChild(property);
            clause.AppendChild(immedval);

            // Create a new expression.
            Expression ex = marketingSystem.Expressions.NewExpression(false);
            ex.Description = "BillBoard Select Expression";
            ex.Body = clause;
            ex.Name = "BillBoard";
            ex.Category = "TargetCondition";
            ex.Save(true);

        }
    }
}

The attachment has a zip file with a console application to create the expression.

See you later, Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Programming Display Windows - Static Version [Part I]

In order to create a static display window supported by the Commerce Server 2007 Marketing System we need a custom DisplayTemplate.

I'll use the DisplayTemplate to format a set of DIVs for each shopping window position. An associated CSS file will be used on the future ASCX control to format the appearance of the window according to your taste.

Let's use the following code to create the DisplayTemplate. Remember, I'm using a vanilla StarterSite installation and all webservices referenced are pointing to the localhost.

//Set the URL to the Web service.
string marketingWebServiceUrl = @"
http://localhost/MarketingWebService/MarketingWebService.asmx";
// Create an instance of the Marketing System agent.
MarketingServiceAgent ma = new MarketingServiceAgent(marketingWebServiceUrl);
MarketingContext marketingSystem = MarketingContext.Create(ma);

//Create a new ad display template.
DisplayTemplate template = marketingSystem.DisplayTemplates.NewDisplayTemplate();
template.Name = "ShoppingWindowItem";
template.Text = "<div id=\"ShoppingWindowAD\"><div id=\"ProductImage\"><img src=\"{%ProductImage%}\"></div><div id=\"ProductTitle\">{%ProductTitle%}</div><div id=\"ProductPrice\">{%ProductPrice%}</div><div id=\"More\">More...</div></div>";

//Create the "ProductImage" property for the new template.
DisplayProperty pi = new DisplayProperty("ProductImage");
pi.Label = "ProductImage";
pi.Source = TemplatePropertySource.Auto;

//Create the "ProductTitle" property for the new template.
DisplayProperty pt = new DisplayProperty("ProductTitle");
pt.Label = "ProductTitle";
pt.Source = TemplatePropertySource.Auto;

//Create the "ProductPrice" property for the new template.
DisplayProperty pp = new DisplayProperty("ProductPrice");
pp.Label = "ProductPrice";
pp.Source = TemplatePropertySource.Auto;

//Add the properties to the template.
template.Properties.Add(pi);
template.Properties.Add(pt);
template.Properties.Add(pp);

//Save the template.
template.Save();

I've packed all the necessary code to create the DisplayTemplate on the attached ZIP file. 

See you on the next post on associating the DisplayTemplate to the product advertisements.

Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Programming Display Windows - Introduction

Hi there,

On the next posts I'd like to show how to build display windows using Commerce Server 2007 Marketing and Catalog Systems. A display window is a webstore requirement of 10 in 10 customers I have worked.

In general customers require a lot more features than a simple display window (including a lot of dynamic integration). But let's start simple and finish with a dynamic marketing display window with integration to the catalog system.

I intend to publish two series: The first one will show how to build a simple static display window for the StarterSite with a custom DisplayTemplate. The second series will show how to build an XML DisplayTemplate and use catalog system queries to create a dynamic display window.

Folks, please comment!!!! You can help improving the content. :) 

Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Commerce Server Catalog Manager and SOAP Limits

If your customer has a lot of categories or products and when using the Catalog Manager to change the sequence you are getting the following error message (I got it today! :)):

"There was an exception running the extensions specified in the config file. Maximum request length exceeded."

Don't worry.

The request length can be modified by adding the following info to the catalog webservice System.Web configuration file:

<system.web>
<httpRuntime maxRequestLength="30270" />
</system.web>

[]'s

This posting is provided "AS IS" with no warranties, and confers no rights.

Cool Tools for Commerce Server (now 2007)

Hi there,

Up in Redmond last week attending the Commerce Server 2007 bootcamp I told Max that would be great to have all the tools demonstrated during the training in a kind of resource kit.

I now about all the difficulties to pack an official resource kit, meanwhile I'm revamping the Nihit Kaul work on Cool Tools for Commerce Server 2002 now for the 2007 version.

Kudos to Max Akbar, Colin Bowern and others...

  • Commerce Server Best Practices Analyzer: This is the Microsoft tool to check your Commerce Server 2007 infrastructure against a set of best practice rules.
  • Commerce Server Capacity Planning Tool: A website with a tool to start your capacity planning. It gives you start point to a more complete capacity plan for your deployment.
  • PackageThis: Max has already posted about this tool and its capacity to convert from new help file formats and documentation available on MSDN to portable/standalone CHM files.
  • PUPViewer 2007: This tool can be used to navigate through PUP file components. Now it is updated to Commerce Server 2007.
  • Securing Commerce Server 2007: Painted yourself in a tight spot configuring CS2007 security accounts, application pool identities, database roles, authorization manager role addignments? Enjoy Max's Secure Commerce Server 2007 tool.
  • Pipeline Component Project Templates: This one packages Visual Studio 2005 project templates for pipeline components development in C# and VB.Net. Kudos to Colin Bowern for this one.
  • Deploying Commerce Server 2007 Sites without Site Packager: Are you trying to automate your Commerce Server website setup and you feel that the CS Site Packager could be more flexible? Colin came up with a set of scripts and tools to create Commerce Server resources, change authorization manager roles, etc.
  • OrderFormViewer 2007: This one allows the visualization of the marshaled_data and search against orders without the Commerce Server Orders Manager.  

Since the GotDotNet workspaces are not available anymore I guess I missed some of the tools demonstrated during the bootcamp.

Max is now updating his website with all the tools @ http://www.commerceservertraining.com/.

Regards, Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Broadcom BCM5708 and Virtual Server Issues

I was helping one of our customers with Microsoft Virtual Server Host Clustering and we faced a strange problem with network connectivity. 

As per Broadcom their BCM5708 (NetXtreme_II) has issues with the Virtual Server and they have a workaround which is disable IPMI using a Broadcom utility.

We did that and everything was working ok when just couple days after Broadcom came up with a new version of their card driver correcting the problem.

So if you are facing problems with broadcom cards and virtual server, please check their website and download the latest driver version.

Regards, Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Inventorying Microsoft Softgrid Streamed Applications

Microsoft Softgrid is a new subject to me, but you guys cannot imagine how well impressed I am. It is the killer application of the century! No more administrative pains with application updates and no more DLL hell on the user's workstation. Cool!

I'm just finishing my first training on the Microsoft Softgrid solution and during the class one of my friends came up with a question on how to get inventory information about the streamed applications being executed on the workstations. My colleague Plínio Queiroz came also with the idea of a sms_def.mof extension to deal with this issue. That's great. We can use the mof extension to collect the softgrid information on the client using WMI and the registry provider and send to the SMS site database. After the inventory collection we can get historical information of applications being executed, when a particular application was deleted, when it was streamed, etc...

The result? We developed a simple mof extension to be used with SMS2003 in order to get the inventory information. If you want to use it, just follow the steps below:

  • Get the default sms_def.mof from the SMS 2003 \SMS\inboxes\clifiles.src\hinv.
  • Include the following code at the end of the sms_def.mof file.

#pragma namespace("\\\\.\\root\\CIMv2")
[dynamic, provider("RegProv"),
ClassContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Softricity\\SoftGrid Client\\CurrentVersion\\Applications")
]
class Win32Reg_SoftGridApplications
{
[key]
string ApplicationName;
[PropertyContext("DescriptionURL")]
string DescriptionURL;
[PropertyContext("OriginalDescriptionURL")]
string OriginalDescriptionURL
};

#pragma namespace("\\\\.\\root\\CIMv2\\sms")
[SMS_Report(TRUE),
SMS_Group_Name("SoftGridApplications"),
SMS_Class_ID("MICROSOFT|SOFTGRIDAPPLICATIONS|1.0")]
class Win32Reg_SoftGridApplications : SMS_Class_Template
{
[SMS_Report(TRUE),key]
string ApplicationName;
[SMS_Report(TRUE)]
string DescriptionURL;
[SMS_Report(TRUE)]
string OriginalDescriptionURL;
};

  • To ensure that your extension is working, compile the MOF file on one workstation with SMS and the Softgrid clients installed. To do that use the mofcomp.exe tool.

 mofcomp sms_def.mof

  • If you are using SMS2003 you need to create a package to compile the mof file on each SMS client. If you are using SMS 2.0 just wait. During the next appropriate cycle the clients will get the updated mof file.

Wait for the SMS client policy update and you can use the Resource Explorer or the report features of SMS to get all the information you need about which applications are running on your Microsoft Softgrid enabled workstations.

Note: We are getting only the name of the application and the location of the OSD, you can extend the sample to get more information. If you improve the extension or if you create cool reports, please send to us...

Curious to see some results? Check the following screenshots:

The SMS Resource Explorer listing the Softgrid streamed applications

The SMS Resource Explorer historical data showing an application deletion (yes, you will know when someone removes a streamed application)

A simple SMS report on Softgrid streamed applications

The SMS report was created using the following SQL statement:

SELECT v_R_System.Netbios_Name0, v_GS_SOFTGRIDAPPLICATIONS.ApplicationName0 AS 'SoftGrid Application',
v_GS_SOFTGRIDAPPLICATIONS.DescriptionUrl0
FROM v_R_System INNER JOIN
v_GS_SOFTGRIDAPPLICATIONS ON v_R_System.ResourceID = v_GS_SOFTGRIDAPPLICATIONS.ResourceID

Regards, Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Subscribing to the refresh cache event in Commerce Server 2007

Are you looking a way to extend the refresh cache webservice method to refresh ASP .Net cache on your Commerce Server 2007 website? If you are using ASP .Net output cache extensively and need to refresh the cache together with CS caches you can subscribe to the CacheRefresh event using the following code.

Subscription

SiteCacheRefresh.CacheRefresh += new System.EventHandler<SiteCacheRefreshEventArgs>(SiteCacheRefresh_CacheRefresh);

Event Handler

public void SiteCacheRefresh_CacheRefresh(object sender, SiteCacheRefreshEventArgs e)

{

}

As a recommendation, use Global.Asax to subscribe to the event. ASP.NET compiles global.asax into a class derived from the HttpApplication class, and then uses the derived class to represent the application.

If you are using a CS farm the event is triggered at all servers!

Regards! Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

The Page Appearance Framework.

Are you curious on how to control the appearance of an ASP .Net pages using design time properties? Guys from Commerce Server team have shown how to deal with this problem. On a preliminary version of the CS2007 Starter Site (that one with came with CS2007 Beta) they use class properties to deal with the appearance of the sample store page framework.

First step is create a new masterpage with a set of DIV files that can be enabled or disabled according with different page layout statuses. 

The second step is create a base class with a property to control the presentation

public abstract class SiteMasterPage : System.Web.UI.MasterPage
{
}

• Layout property: Control the appearance of the DIV areas inside the masterpage. Depending on context, the background code can change the layout of the page.

Now you need to create a new masterpage and insert code to deal with the properties:

• OnPreRender event: Deal with layout. Activating or deactivating DIVs according to the Layout properties

protected override void OnPreRender(EventArgs e)
{
 switch (this.LayoutStyle)
   {
  //se for mínimo, remove o banner, os sidebars, o menu e o rodapé.
            // deixa só o mainpagecontent
            case PageLayoutStyle.Minimal:
                this.adbanner.Visible = false;
                this.sidebar_a.Visible = false;
                this.sidebar_b.Visible = false;
                this.footer.Visible = false;
                this.menu.Visible = false;
                break;
  case PageLayoutStyle.Full:
      this.adbanner.Visible = true;
                this.sidebar_a.Visible = true;
                this.sidebar_b.Visible = true;
                this.footer.Visible = true;
                this.menu.Visible = true;
                break;
            }

            base.Page.Title = this.title; //ajusta o título da página
            base.OnPreRender(e); //executa a base do prerender
}

To get the design time class properties you can use a piece of code like the following one:

settings = PageSettings.GetPageSettings(HttpContext.Current.CurrentHandler.GetType());

internal static PageSettings GetPageSettings(Type type)
{
    if (type == null)
    {
        throw new ArgumentNullException("type");
    }
    if (!type.IsSubclassOf(typeof(Page)))
    {
        throw new ArgumentException("SubClass", "type");
    }
    if (!PageSettings.typeCache.ContainsKey(type))
    {
        lock(typeCache)
        {
            // Não está em cache, temos que popular.
            if (!PageSettings.typeCache.ContainsKey(type))
            {
                string pageGroup = null;
                bool isSecure = false;
                PageLayoutStyle layoutStyle = PageLayoutStyle.Full;
                object[] attributes = type.GetCustomAttributes(true);
                foreach (Attribute attribute in attributes)
                {
                    if (typeof(PageLayoutAttribute).IsInstanceOfType(attribute))
                    {
                        layoutStyle = ((PageLayoutAttribute)attribute).LayoutStyle;
                    }
                }
                PageSettings.typeCache.Add(type, new PageSettings(layoutStyle, isSecure, pageGroup));
            }
        }

    }
    return PageSettings.typeCache[type];
}

At design time, we just need to tell how the page will look using the following approach:

[PageLayout(PageLayoutStyle.Full)]
public partial class _Default : System.Web.UI.Page
{

}

Remember that your ASPX page must be based on a MasterPage created from the custom base class.

public partial class StandardLayout : SiteMasterPage
{
...
}

Regards, Cris.
 

This posting is provided "AS IS" with no warranties, and confers no rights.

The Visual Studio 2005 Code-Beside Dilemma!

Did you know that? With Visual Studio 2003 we were able to extend the System.Web.UI.Page class and create new properties for WebForms. Test yourself, using VS2003, create a new property for your class (derived from System.Web.UI.Page), create a new ASP .Net page based on your new class and you will see the created property it on the Visual Studio properties page for the ASPX.

When saving the page, you will see that the code behind is automatically changed to include the property values. It is a very easy approach to create custom properties on ASP .Net web pages.

A couple of weeks ago I was working with one of our customers and I said that he could use the properties approach to easily customize the appearance of his ASP .Net web pages. But what’s my surprise when I noticed that this is not working on Visual Studio 2005.

Ok. Know the reason for such thing not work anymore became a question of honor. After post some questions on our internal lists and search a little bit on the Internet I figured out the reason.

Before begin the explanation, I’d like to let you know that it is a known issue reported at http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=105510.

Let’s try to explain.

According to my research there was a design change in the product. Basically in Visual Studio 2005 RTM, the code behind file and the generated stub are compiled into the base class, and the actual ASP .Net page inherits the base class.

The V1.X code behind model (seen on the Visual Studio 2003) is still supported by the runtime, however, you cannot use Visual Studio 2005 for editing the V1.X style pages.
 
The code that was being generated by Visual Studio 2003 IDE is now moved to the partial class that is automatically generated during compilation. If you just want to see what is in the generated class, you can set the page to debug mode and look for the generated files under the ASP.NET temporary folder.

The model is changed to allow updatable pages after compilation. To achieve this, the product group came up with the current model which is very similar to V1.X that the codes behind files are still compiled into the base classes. The only difference is that the control field declarations and the class constructor are now automatically generated instead of injected at design time.

So the collateral effect appeared. As the control field declarations are automatically generated at the compilation time we cannot store the adjusted values for custom properties on the appropriate place. Therefore we need a different approach to implement this kind of functionality.

I managed to implement (with the help of a sort of samples) a mechanism that can be used to coordinate the appearance of ASP .Net pages at design time using class properties injected manually on the code. I’ll show how to do that on another post. Stay tuned!

Bye!!

This posting is provided "AS IS" with no warranties, and confers no rights.

How to setup Live Communications Server 2005 and Cisco Call Manager 4.1 to VoIp –PSTN convergence

Hello! Now I want to share with you some tips on configuring LCS and its client  Office Communicator to originate VoIp calls to a Cisco SCCP IP Phone or conventional PSTN phones through a Cisco Call Manager 4.1 SR3.

 

Many companies setup Cisco Telephony over IP environments and don’t know they can use Office Communicator and LCS 2005 to place calls to the VoIp and PSTN clouds just using the already in-place Cisco infrastructure.

 

I mean, the companies do not need a special gateway just to make VoIP and PSTN calls from Office Communicator using their in-place Cisco Call Manager 4.1.

 

In fact, they still need a gateway if the goal is to make signaling (3PCC/CSTA) integration.

 

Actually I have a customer using Cisco Call Manager 4.1 to place VoIP calls to all their IP and PSTN phones using the integration already made between the CCM 4.1 and the corporative PBX.

 

Before to start with the configuration steps I’d like to list what will work after the setup:

 

  • Calls can be placed from LCS (Office Communicator) to another VoIP phone “connected” through CCM.
  • Calls can be placed from LCS (Office Communicator) to PSTN phones through CCM. 

What will not work?

 

  • Transfer, conferencing and call forwarding from Office Communicator (LCS) side. [Requires a CSTA/3PCC gateway]

First let’s check the network topology.

 

 

 

Now the steps.

  

  1. Open the Microsoft Office Live Communications Server 2005 MMC administrative console.
  2. Expand the forest node, the domain node and the Live Communications Servers and Pools node.
  3. Click with the right button on the LCS Pool and create an outbound static route pointing to the Cisco Call Manager with the following information:
    • User: *
    • Domain: <LCS POOL FQDN>
    • Next Hop IP address: the IP address used by Cisco Call Manager
    • Next Hop Transport: TCP
    • Port: 5060
    • Phone URI: Checked
  4. On the Host Authorization Tab, include the IP of the Cisco Call Manager as a Authorized Host. Use the following options:
    1. Server IP Address: the IP address used by Cisco Call Manager
    2. Settings:
      • i.      Throttle as Server: Checked
      • Treat as Authenticated: Checked
  5. Open the CCM Administration web page and create an incoming partition (probably it will already have one).
  6. Create a new SIP Trunk with the following options:

Device Information

 

    1. Device name: LCSSIP
    2. Device Pool: Default
    3. Call Classification: Use System Default
    4. Media Resource Group List: Select appropriate list.
    5. Location: None
    6. AAR Group: None
    7. Media termination point required: Checked
    8. Destination address: the IP address used by LCS
    9. Destination port: 5060
    10. Incoming port: 5060
    11. Outgoing transport type: TCP
    12. Preferred Originating codec: 711ulaw

Call Routing Information

 

a.      Significant Digits: All

b.      Connected Line ID Presentation: Default

c.      Connected Name Presentation: Default

 

  1. Create a Media Termination Point using the Add Media Termination Point on the CCM web administration.

You also need to setup a registry key (manually or using Group Policies) to enable the PC2Phone functionality on your Office Communicator.

 

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Communicator]
"EnablePC2Phone"=dword:00000001

On the COMMUNICATOR.ADM template this configuration is named "Enable Computer to Phone Calls".

 

Now go to the Office Communicator and just type the phone number on the Find box, click on Call to place Voip or PSTN calls through the CCM 4.1. You will also notice that the combo box on the side of your contacts is now enabled.

 

Regards, Cris.

This posting is provided "AS IS" with no warranties, and confers no rights.

Credential delegation and IIS Kerberos authentication

I’m back. I’d like to share with you some tips on how to enable Kerberos authentication and credential delegation on IIS6.0. I’ve been beating my head against the wall to see this thing working on one of our customers.

 

I didn’t know how much this kind of integrated authentication with Kerberos has to do with DNS and reverse resolution. When you find yourself with problems setting up Kerberos, ALWAYS check the DNS before start.

 

One good KB article showing how to setup Kerberos and delegation is

 

  • Kerberos authentication and troubleshooting delegation issues http://support.microsoft.com/default.aspx?scid=kb;en-us;907272  

If you are using ServerXMLHttp COM component as my customer was, keep in mind that you also need setup the WinInet proxy using proxycfg. The following articles show how to do that

 

  • How To Use Kerberos with the ServerXMLHTTP Component in MSXML http://support.microsoft.com/default.aspx?scid=kb;en-us;314404
  • You may need to run the Proxycfg tool for ServerXMLHTTP to work http://support.microsoft.com/kb/289481/EN-US/

Have you followed all the instructions and Kerberos is not working? I have another tip:

 

Call PSS and ask them for a copy of the DelegConfig Tool. It’s a great tool developed by Brian Murphy-Booth that check all the related settings to have Kerberos and delegation working.

 

Best Regards, Cris.

 

This posting is provided "AS IS" with no warranties, and confers no rights.

More Posts Next page »
Page view tracker