Create MMC ListView SnapIn using C#

Introduction

The MMC list view shows a list of result nodes in the results pane. This is the most commonly used view that is particularly suited to snap-ins that are designed to manage a dynamic list of items. The MMC list view supports small icons, large icons, lists, and report views. It also supports multi-select and single select operations on items, and a multiple column view with the ability to sort by column.

Using the code

Please make sure that you have gone through the previous articles, if you are a beginner. This article demonstrates how to create a snap-in that uses an MMC list view. I have started by creating a C# class library. Add a reference to Microsoft.ManagementConsole.

Inherit the main class from the SnapIn class

Collapse
         
[SnapInSettings("{F98E33A4-1DA5-414c-8576-B3582433F8AB}",
DisplayName = "My Custom MmcListView",
Description = "My Custom MmcListView")]
public class MMCListViewSnapInClass : SnapIn

Add another class which is inheriting from the SnapInInstaller

Collapse
[RunInstaller(true)]
public class MMCListViewSnapInstallerSupport : SnapInInstaller
{

}

Initializes a new instance of the MMCListViewSnapInClass class. Create a Root Node and set the properties.

Collapse
    // Create a message view for the root node.

MmcListViewDescription lvd = new MmcListViewDescription();
lvd.DisplayName = "My Special MMCListView";
lvd.ViewType = typeof(RootListView);
lvd.Options = MmcListViewOptions.ExcludeScopeNodes;

// Attach the view to the root node.
this.RootNode.ViewDescriptions.Add(lvd);
this.RootNode.ViewDescriptions.DefaultIndex = 0;

In the above code I have created a message view for the root node and attach the view to the root node. The message view is created as RootListView class . This is a new class inherited from MmcListView. The new class looks like this.

Collapse
  using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ManagementConsole;
using System.Windows.Forms;

namespace MMCListViewSnapIn
{
class RootListView : MmcListView
{
///
/// Initializes a new instance of the RootListView class.
///
public RootListView()
{
}

Since this RootListView class is attached to the Root Node MyMMCListView as MmcListView, this will get loaded on the content pane when Root Node is selected in the MMC tree region.

We can override the OnInitialize to customise the initial view of the content pane.

Collapse
protected override void OnInitialize(AsyncStatus status)
{
base.OnInitialize(status);
// Your Initialization code can be added here
}

I have added another 5 more MmcListView derived classes which bascailly attached to each child node of the tree. This is the screen shot of the IDE. This may help you sometimes, if you miss something on the go.

mmclistview2.jpg

Let me explain one of the MmcListView derived class. I am picking MyCustomSelistView class.

Collapse
  using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ManagementConsole;
using System.Windows.Forms;

namespace MMCListViewSnapIn
{
class MyCusomtSelistView:MmcListView
{

///
/// Initializes a new instance of the MyCusomtSelistView class.
///
public MyCusomtSelistView()
{
}

Override OnInitialize function to set the default setting for the content pane.

Collapse
   protected override void OnInitialize(AsyncStatus status)
{
// this does the default handling
base.OnInitialize(status);

// Create a set of columns for use in the list view
// Define the default column title
this.Columns[0].Title = "Name";
this.Columns[0].SetWidth(300);

// Add detail column
// another way to add the column
this.Columns.Add(new MmcListViewColumn("Value", 500));

// Set to show all columns on the UI
this.Mode = MmcListViewMode.Report; // default (set for clarity)

// Set to show refresh as an option
this.SelectionData.EnabledStandardVerbs = StandardVerbs.Refresh;

// Load the list with values
Refresh();

}

///
/// Loads the list view with data.
///
public void Refresh()
{
// Clear existing information.
this.ResultNodes.Clear();

// Use fictitious data to populate the lists.
string[][] details = { new string[] {"Full Name ", "Gigy Joseph"},
new string[] {"Place", "West Columbia, SC"},
new string[] {"Company", "NCR"},
new string[] {"Curr.Technology", "C#"},
new string[] {"Prev. Technology", "VC++"},
new string[] {"Native", "India"},
new string[] {"Age", "No way :) "},

};

// Populate the list.
foreach (string[] detail in details)
{
ResultNode node = new ResultNode();
node.DisplayName = detail[0];
node.SubItemDisplayNames.Add(detail[1]);

this.ResultNodes.Add(node);
}
}

I have added two columns as Name and Value.Show all columns on the UI by setting Mode as MmcListViewMode.Report. The Refresh function loads data to the list view.

Collapse
// If there are no selected nodes, then this method simply clears 
// the selection data; otherwise, it populates the selection data. It also
// adds a new action that shows the selected items to the actions pane.

protected override void OnSelectionChanged(SyncStatus status)
{

if (this.SelectedNodes.Count == 0)
{
this.SelectionData.Clear();
}
else
{
this.SelectionData.Update(GetDetails(), this.SelectedNodes.Count > 1,
null, null);
this.SelectionData.ActionsPaneItems.Clear();
this.SelectionData.ActionsPaneItems.Add(new Microsoft.ManagementConsole.Action("Show Selected",
"Shows list of selected Users.", -
1, "ShowSelected"));
this.SelectionData.ActionsPaneItems.Add(new Microsoft.ManagementConsole.Action("Say Hello",
"Say Hello.", -1, "Say Hello"));
}

}

We have overriden OnSelectionChanged , this helps to customize the context menu on the action pane. Here we have added two menuitems and actions for those items.

Collapse
// this defines what happens when an action is selected. 
// Here, we have only one action and we invoke
// the ShowSelected method when it is selected.

protected override void OnSelectionAction
(Microsoft.ManagementConsole.Action action,
AsyncStatus status)
{
switch ((string)action.Tag)
{
case "ShowSelected":
{
ShowSelected();
break;
}
case "Say Hello":
{
MessageBox.Show("Hello, How are you?");
break;
}
}

}

mmclistview3.jpg

Collapse
/// 
/// Shows selected items.
///
private void ShowSelected()
{
MessageBox.Show("Selected Item: \n" + GetDetails());
}

private string GetDetails()
{
StringBuilder nodedetails = new StringBuilder();

foreach (ResultNode resultNode in this.SelectedNodes)
{
nodedetails.Append(resultNode.DisplayName + ": " +
resultNode.SubItemDisplayNames[0].ToString() + "\n");
}
return nodedetails.ToString();
}

When user select the ShowSelected menu item ShowSelected() functions gets called. This will show up a message box with the selected elements details.

mmclistview4.jpg

This also allows multi selection.

mmclistview5.jpg

Selection of menu item, Say Hello just pops up a message box. We can override the OnRefresh function as below.

Collapse
 protected override void OnRefresh(AsyncStatus status)
{
MessageBox.Show("Need to implement....");
}

Adding new child elements to the Root Node happens like this.

Collapse
    /// Initializes a new instance of the MMCListViewSnapInClass class.
///
public MMCListViewSnapInClass()
{

// Create the root node.
this.RootNode = new ScopeNode();
this.RootNode.DisplayName = "My MMCListView";


// Create a message view for the root node.
MmcListViewDescription lvd = new MmcListViewDescription();
lvd.DisplayName = "My Special MMCListView";
lvd.ViewType = typeof(RootListView);
lvd.Options = MmcListViewOptions.ExcludeScopeNodes;

// Attach the view to the root node.
this.RootNode.ViewDescriptions.Add(lvd);
this.RootNode.ViewDescriptions.DefaultIndex = 0;

// Creating the child Nodes to the root Node
// Also specified names for each node

ScopeNode scopeOne = new ScopeNode();
scopeOne.DisplayName = "Gigy";

// Create a message view for the scopeOne.

MmcListViewDescription lvdOne = new MmcListViewDescription();
lvdOne.DisplayName = "Gigy's MMCListView";
lvdOne.ViewType = typeof(MyCusomtSelistView);
lvdOne.Options = MmcListViewOptions.ExcludeScopeNodes;

scopeOne.ViewDescriptions.Add(lvdOne);
scopeOne.ViewDescriptions.DefaultIndex = 0;

this.RootNode.Children.Add(scopeOne);

........

so on ......

->Read More...

Setup-Dialogs - Own BannerBitmap and SplashBitmap

Introduction

With setup projects provides with Visual studio I want to have my own bitmaps. In addition it is necessary in every dialogue to integrate own bitmap about the file explorer. This article describes like this is made unique in general for all setup projects.

Banner.gif

The BannerBitmap

Splash.gif

The SplashBitmap

Background

With a lot of setup to projects the production with Visual studio is complete enough. Then the purchase of special software for this is too expensive. Nevertheless, should receive dialoge a professional appearance.

Where the dialogues are deposited

The dialogues are in localised subdirectories from:

Collapse
C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\Deployment\VsdDialogs

Own BannerBitmap

For Neutral in the subdirectory 0 and for German in the subdirectory in 1031.

The normally used bitmaps are deposited in the file VsdUserInterface.wim.

VsdUserInterface.gif

If they open the file VsdUserInterface.wim with Orca and they click in the table Binary in the line DefBannerBitmap the field Data.

A dialogue in them opens to itself her own banner bitmap can select and integrate.

This bitmap must have 542 x 63 pixels.

Own SplashBitmap

If they lay in VsdUserInterface.wim in the table Binary a new entry DefSplashBitmap.

If they select in the dialogue her SplashBitmap and they integrate this with it.

This bitmap must have 477 x 318 pixels.

If they carry out in the dialogues VsdSplashDlg.wid and VsdAdminSplashDlg.wid the following changes.

VsdSplashDlg1.gif

In the table Control and the line SplashForm they change the field of attribute in 1 and the field Text in DefSplashBitmap.

VsdSplashDlg2.gif

Indians table ModuleConfiguration give them in the line SplashBitmap in the field DefaultValue the text DefSplashBitmap.

Final remark

These changes must carry out them in every used linguistic subdirectory.

License

This article, along with any associated source code and files, is licensed under

->Read More...

Open Source Dotnet

Vista Style Button in C#


Screenshot - Screenshot.jpg

Introduction

I have a habit of using the standard Windows controls as little as possible. If I can write my own control to do it then I will. It's kinda like reinventing the wheel but adding spinners. Anyways this is an article on a Vista Style button that I made. Unlike the progress bar control I wrote, I didn't create it in Photoshop first. I just designed it in code, as a result it's not quite as nice looking as the actual Vista buttons. The actual button itself can be made very un-Vista-ish if you want to by changing the colours but the default look for the button is the one in the top left.

Coppy Right : http://www.codeproject.com/KB/buttons/VistaButton.aspx


->Read More...

Generate your own proxy for ADO.Net Data Services on client side

Introduction

First of all, please accept my appologizes for my poor english :)

This article speak about creating entities proxy classes for your own need.

Problem

The proxy class generated from a ADO.Net Data Service is simple and only helps for standard CRUD scenarii. But as soon as you want to make something complex or special you will find some restrictions. If you need some features that do not exist inside this proxy you can write them by adding a new partial class to your project or use reflexion. You can make this easily to add some features such as a static method or a simple utility method. But if you have to make a feature shared between all your entities or something that depends on your entities semantics you won't be able to use this way.

You need to use an automatic generation of a proxy class that contains the features you need. That's the thing we will make here : create new set of partial classes to complete existing partial class of the proxy with our needs or create the whole set of proxy classes.

Our answer

In order to generate our own class we will have to read metadatas from the web data service.

The generation will use the msxsl.Exe tool from microsoft : it build a result from an xml and a xslt file. The "result" will be our proxy classes, the "xml" will be the $metadata result of the web data service and the "xslt" the job we have to make here.

Create the Data base

Very simple step. Microsoft offer some T-Sql scripts to generate a sample database. Go here to find it. Install the script to create to own base.

The Solution

We are not here to learn how to create those projects. So just download the zip gived with this article to get the entire solution. You will find in it :

  • A web project with an ADO.net data service
  • An entities project with an edmx.
  • A client project.

gd01.png

In the solution directory i added a Tools directory where you can find the msxsl.exe tools.

gd02.png

Before launching the service we have to make a link between the edmx and the data base.

Inside the web.config file change the end of the connexion string to make a connection to the school database :

Collapse
<add name="SchoolEntities"
connectionString="metadata=res://*/SchoolModel.csdl|res://*/SchoolModel.ssdl|res://*/SchoolModel.msl;
provider=System.Data.SqlClient;provider connection string="Data Source=localhost\sqlexpress;
Initial Catalog=School;Integrated Security=True;MultipleActiveResultSets=True
""

providerName="System.Data.EntityClient" />

Start the web data service by right click on the WebDataService.svc file on the solution explorer and selecting "Open in Browser". You will see something like this :

gd03.png

Our service is ready.

Generation needs metadatas (xml part)

We need a Xml file that contains all informations about the entities of the school model and their relation. Just add the keyword $metadata to the end of the web data service url like this :

gd04.png

You see now a complete description of the school model :

Collapse
xml version="1.0" encoding="utf-8" standalone="yes"?>
<edmx:Edmx href="%22%22%22%22http://schemas.microsoft.com/ado/2007/06/edmx%22%3E%3Cedmx:DataServices%3E%3CSchema%3E%3CEntityType%22%22%22%22">>
<edmx:DataServices>
<Schema>
<EntityType
Name="Course">
<Key>
<PropertyRef Name="CourseID" />
</Key>
<Property Name="CourseID" Type="Edm.Int32" Nullable="false" />
<Property Name="Title" Type="Edm.String" Nullable="false" MaxLength="100" Unicode="true" FixedLength="false" />
<Property Name="Credits" Type="Edm.Int32" Nullable="false" />
<NavigationProperty Name="Department" Relationship="SchoolModel.FK_Course_Department" FromRole="Course" ToRole="Department" />
<NavigationProperty Name="CourseGrade" Relationship="SchoolModel.FK_CourseGrade_Course" FromRole="Course" ToRole="CourseGrade" />
<NavigationProperty Name="OnlineCourse" Relationship="SchoolModel.FK_OnlineCourse_Course" FromRole="Course" ToRole="OnlineCourse" />
<NavigationProperty Name="OnsiteCourse" Relationship="SchoolModel.FK_OnsiteCourse_Course" FromRole="Course" ToRole="OnsiteCourse" />
<NavigationProperty Name="Person" Relationship="SchoolModel.CourseInstructor" FromRole="Course" ToRole="Person" />
</EntityType>
<EntityType Name="CourseGrade">
<Key>
<PropertyRef Name="EnrollmentID" />
</Key>
<Property Name="EnrollmentID" Type="Edm.Int32" Nullable="false" />
<Property Name="Grade" Type="Edm.Decimal" Nullable="true" Precision="3" Scale="2" />
<NavigationProperty Name="Course" Relationship="SchoolModel.FK_CourseGrade_Course" FromRole="CourseGrade" ToRole="Course" />
<NavigationProperty Name="Person" Relationship="SchoolModel.FK_CourseGrade_Student" FromRole="CourseGrade" ToRole="Person" />
</EntityType>
<EntityType Name="Department">
<Key>
<PropertyRef Name="DepartmentID" />
</Key>
<Property Name="DepartmentID" Type="Edm.Int32" Nullable="false" />
<Property Name="Name" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="Budget" Type="Edm.Decimal" Nullable="false" Precision="19" Scale="4" />
<Property Name="StartDate" Type="Edm.DateTime" Nullable="false" />
<Property Name="Administrator" Type="Edm.Int32" Nullable="true" />
<NavigationProperty Name="Course" Relationship="SchoolModel.FK_Course_Department" FromRole="Department" ToRole="Course" />
</EntityType>
<EntityType Name="OfficeAssignment">
<Key>
<PropertyRef Name="InstructorID" />
</Key>
<Property Name="InstructorID" Type="Edm.Int32" Nullable="false" />
<Property Name="Location" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="Timestamp" Type="Edm.Binary" Nullable="false" MaxLength="8" FixedLength="true" />
<NavigationProperty Name="Person" Relationship="SchoolModel.FK_OfficeAssignment_Person" FromRole="OfficeAssignment" ToRole="Person" />
</EntityType>
<EntityType Name="OnlineCourse">
<Key>
<PropertyRef Name="CourseID" />
</Key>
<Property Name="CourseID" Type="Edm.Int32" Nullable="false" />
<Property Name="URL" Type="Edm.String" Nullable="false" MaxLength="100" Unicode="true" FixedLength="false" />
<NavigationProperty Name="Course" Relationship="SchoolModel.FK_OnlineCourse_Course" FromRole="OnlineCourse" ToRole="Course" />
</EntityType>
<EntityType Name="OnsiteCourse">
<Key>
<PropertyRef Name="CourseID" />
</Key>
<Property Name="CourseID" Type="Edm.Int32" Nullable="false" />
<Property Name="Location" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="Days" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="Time" Type="Edm.DateTime" Nullable="false" />
<NavigationProperty Name="Course" Relationship="SchoolModel.FK_OnsiteCourse_Course" FromRole="OnsiteCourse" ToRole="Course" />
</EntityType>
<EntityType Name="Person">
<Key>
<PropertyRef Name="PersonID" />
</Key>
<Property Name="PersonID" Type="Edm.Int32" Nullable="false" />
<Property Name="LastName" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="FirstName" Type="Edm.String" Nullable="false" MaxLength="50" Unicode="true" FixedLength="false" />
<Property Name="HireDate" Type="Edm.DateTime" Nullable="true" />
<Property Name="EnrollmentDate" Type="Edm.DateTime" Nullable="true" />
<NavigationProperty Name="CourseGrade" Relationship="SchoolModel.FK_CourseGrade_Student" FromRole="Person" ToRole="CourseGrade" />
<NavigationProperty Name="OfficeAssignment" Relationship="SchoolModel.FK_OfficeAssignment_Person" FromRole="Person"
ToRole="OfficeAssignment" />
<NavigationProperty Name="Course" Relationship="SchoolModel.CourseInstructor" FromRole="Person" ToRole="Course" />
</EntityType>
<Association Name="FK_Course_Department">
<End Role="Department" Type="SchoolModel.Department" Multiplicity="1" />
<End Role="Course" Type="SchoolModel.Course" Multiplicity="*" />
</Association>
<Association Name="FK_CourseGrade_Course">
<End Role="Course" Type="SchoolModel.Course" Multiplicity="1" />
<End Role="CourseGrade" Type="SchoolModel.CourseGrade" Multiplicity="*" />
</Association>
<Association Name="FK_OnlineCourse_Course">
<End Role="Course" Type="SchoolModel.Course" Multiplicity="1" />
<End Role="OnlineCourse" Type="SchoolModel.OnlineCourse" Multiplicity="0..1" />
<ReferentialConstraint>
<Principal Role="Course">
<PropertyRef Name="CourseID" />
</Principal>
<Dependent Role="OnlineCourse">
<PropertyRef Name="CourseID" />
</Dependent>
</ReferentialConstraint>
</Association>
<Association Name="FK_OnsiteCourse_Course">
<End Role="Course" Type="SchoolModel.Course" Multiplicity="1" />
<End Role="OnsiteCourse" Type="SchoolModel.OnsiteCourse" Multiplicity="0..1" />
<ReferentialConstraint>
<Principal Role="Course">
<PropertyRef Name="CourseID" />
</Principal>
<Dependent Role="OnsiteCourse">
<PropertyRef Name="CourseID" />
</Dependent>
</ReferentialConstraint>
</Association>
<Association Name="FK_CourseGrade_Student">
<End Role="Person" Type="SchoolModel.Person" Multiplicity="1" />
<End Role="CourseGrade" Type="SchoolModel.CourseGrade" Multiplicity="*" />
</Association>
<Association Name="FK_OfficeAssignment_Person">
<End Role="Person" Type="SchoolModel.Person" Multiplicity="1" />
<End Role="OfficeAssignment" Type="SchoolModel.OfficeAssignment" Multiplicity="0..1" />
<ReferentialConstraint>
<Principal Role="Person">
<PropertyRef Name="PersonID" />
</Principal>
<Dependent Role="OfficeAssignment">
<PropertyRef Name="InstructorID" />
</Dependent>
</ReferentialConstraint>
</Association>
<Association Name="CourseInstructor">
<End Role="Course" Type="SchoolModel.Course" Multiplicity="*" />
<End Role="Person" Type="SchoolModel.Person" Multiplicity="*" />
</Association>
</Schema>

</edmx:DataServices>
</edmx:Edmx>

The proxy class will be generated from this xml.

The xslt file

The xslt file will generate the entities classes proxy. Here is the content of the xslt file :

Collapse
xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet>
<xsl:output method="text"/>

<xsl:template match="/edmx:Edmx">
<xsl:apply-templates select="edmx:DataServices" />
<xsl:apply-templates select="edmx:Queries">
</xsl:apply-templates>
</xsl:template>

<xsl:template match="edmx:DataServices">
<xsl:text>[assembly: global::System.Data.Objects.DataClasses.EdmSchemaAttribute()] </xsl:text>
<xsl:apply-templates select="schema:Schema">
<xsl:sort select="@Namespace"/>
</xsl:apply-templates>
</xsl:template>

<xsl:template match="schema:Schema">
<xsl:apply-templates select="schema:EntityContainer" mode="AssemblyMetadatas"/>
<xsl:text>
</xsl:text>
<xsl:text>namespace </xsl:text>
<xsl:value-of select="@Namespace"/>
<xsl:text>
{</xsl:text>
<xsl:apply-templates select="schema:EntityContainer" mode="EntitiesContext">
<xsl:with-param name="NamespaceName" select="@Namespace"></xsl:with-param>
</xsl:apply-templates>
<xsl:apply-templates select="schema:EntityType">
<xsl:sort select="@Name"/>
</xsl:apply-templates>
<xsl:text> } </xsl:text>
</xsl:template>

<xsl:template match="schema:EntityContainer" mode="AssemblyMetadatas">
<xsl:apply-templates select="schema:AssociationSet">
<xsl:sort select="@Name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="schema:EntityContainer" mode="EntitiesContext">
<xsl:param name="NamespaceName" select="NamespaceName"></xsl:param>
<xsl:text> public partial class </xsl:text>
<xsl:value-of select="@Name"></xsl:value-of>
<xsl:text> : global::System.Data.Services.Client.DataServiceContext </xsl:text>
<xsl:text> { </xsl:text>
<xsl:text> public </xsl:text>
<xsl:value-of select="@Name"></xsl:value-of>
<xsl:text>(global::System.Uri serviceRoot) : base(serviceRoot) </xsl:text>
<xsl:text> { </xsl:text>
<xsl:text> this.OnContextCreated(); </xsl:text>
<xsl:text> } </xsl:text>
<xsl:text> partial void OnContextCreated(); </xsl:text>
<xsl:apply-templates select="schema:EntitySet" mode="Properties">
<xsl:sort select="@Name"/>
<xsl:with-param name="NamespaceName" select="$NamespaceName"></xsl:with-param>
</xsl:apply-templates>
<xsl:apply-templates select="schema:EntitySet" mode="Add">
<xsl:sort select="@Name"/>
<xsl:with-param name="NamespaceName" select="$NamespaceName"></xsl:with-param>
</xsl:apply-templates>
<xsl:text> } </xsl:text>
</xsl:template>

<xsl:template match="schema:EntitySet" mode="Properties">
<xsl:param name="NamespaceName" select="NamespaceName"></xsl:param>
<xsl:text> public System.Data.Services.Client.DataServiceQuery<</xsl:text>
<xsl:value-of select="substring-after(@EntityType, concat($NamespaceName, '.'))"/>
<xsl:text>> </xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> { </xsl:text>
<xsl:text> get </xsl:text>
<xsl:text> { </xsl:text>
<xsl:text> if (this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> == null) </xsl:text>
<xsl:text> { </xsl:text>
<xsl:text> this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> = base.CreateQuery<</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>>("[</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>]"); </xsl:text>
<xsl:text> } </xsl:text>
<xsl:text> return this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>; </xsl:text>
<xsl:text> } </xsl:text>
<xsl:text> } </xsl:text>
<xsl:text> private global::System.Data.Services.Client.DataServiceQuery<</xsl:text>
<xsl:value-of select="substring-after(@EntityType, concat($NamespaceName, '.'))"/>
<xsl:text>> _</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>; </xsl:text>
</xsl:template>
<xsl:template match="schema:EntitySet" mode="Add">
<xsl:param name="NamespaceName" select="NamespaceName"></xsl:param>
<xsl:text> public void AddTo</xsl:text>
<xsl:value-of select="substring-after(@EntityType, concat($NamespaceName, '.'))"/>
<xsl:text>(</xsl:text>
<xsl:value-of select="substring-after(@EntityType, concat($NamespaceName, '.'))"/>
<xsl:text> @</xsl:text>
<xsl:value-of select="substring-after(@EntityType, concat($NamespaceName, '.'))"/>
<xsl:text>) </xsl:text>
<xsl:text> { </xsl:text>
<xsl:text> base.AddObject("</xsl:text>
<xsl:value-of select="substring-after(@EntityType, concat($NamespaceName, '.'))"/>
<xsl:text> ", @</xsl:text>
<xsl:value-of select="substring-after(@EntityType, concat($NamespaceName, '.'))"/>
<xsl:text>); </xsl:text>
<xsl:text> } </xsl:text>
</xsl:template>

<xsl:template match="schema:AssociationSet">
<xsl:param name="NamespaceName" select="NamespaceName"></xsl:param>
<xsl:variable name="AssociationName" select="@Name"></xsl:variable>
<xsl:variable name="FirstRole" select="schema:End[1]/@Role"></xsl:variable>
<xsl:variable name="SecondRole" select="schema:End[2]/@Role"></xsl:variable>
<xsl:variable name="AssociationFirstType"
select="../../schema:Association[@Name=$AssociationName]/schema:End[@Role=$FirstRole]/@Type"></xsl:variable>
<xsl:variable name="AssociationFirstMultiplicity"
select="../../schema:Association[@Name=$AssociationName]/schema:End[@Role=$FirstRole]/@Multiplicity"></xsl:variable>
<xsl:variable name="AssociationSecondType"
select="../../schema:Association[@Name=$AssociationName]/schema:End[@Role=$SecondRole]/@Type"></xsl:variable>
<xsl:variable name="AssociationSecondMultiplicity"
select="../../schema:Association[@Name=$AssociationName]/schema:End[@Role=$SecondRole]/@Multiplicity"></xsl:variable>
<xsl:text>[assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("</xsl:text>
<xsl:value-of select="$NamespaceName"/>
<xsl:text>", "</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>", "</xsl:text>
<xsl:value-of select="$FirstRole"/>
<xsl:text>", global::System.Data.Metadata.Edm.RelationshipMultiplicity.</xsl:text>
<xsl:choose>
<xsl:when test="$AssociationFirstMultiplicity='*'">
<xsl:text>Many</xsl:text>
</xsl:when>
<xsl:when test="$AssociationFirstMultiplicity='1'">
<xsl:text>One</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>ZeroOrOne</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>, typeof(</xsl:text>
<xsl:value-of select="$AssociationFirstType"/>
<xsl:text>), "</xsl:text>
<xsl:value-of select="$SecondRole"/>
<xsl:text>", global::System.Data.Metadata.Edm.RelationshipMultiplicity.</xsl:text>
<xsl:choose>
<xsl:when test="$AssociationSecondMultiplicity='*'">
<xsl:text>Many</xsl:text>
</xsl:when>
<xsl:when test="$AssociationSecondMultiplicity='1'">
<xsl:text>One</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>ZeroOrOne</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>, typeof(</xsl:text>
<xsl:value-of select="$AssociationSecondType"/>
<xsl:text>))] </xsl:text>
</xsl:template>

<xsl:template match="schema:EntityType">
<xsl:text> </xsl:text>
<xsl:text> #region class </xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> </xsl:text>
<xsl:text> [global::System.Serializable()]</xsl:text>
<xsl:text> [global::System.Data.Services.Common.DataServiceKeyAttribute(</xsl:text>
<xsl:for-each select="schema:Key/schema:PropertyRef">
<xsl:text>"</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:text>)] </xsl:text>
<xsl:text> public partial class </xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> : global::System.ComponentModel.INotifyPropertyChanged
{ </xsl:text>

<xsl:text> #region Fields </xsl:text>
<xsl:apply-templates select="schema:Property" mode="FieldsDeclaration">
<xsl:sort select="@Name"/>
</xsl:apply-templates>
<xsl:apply-templates select="schema:NavigationProperty" mode="FieldsDeclaration">
<xsl:sort select="@Name"/>
</xsl:apply-templates>
<xsl:text> #endregion //Fields </xsl:text>

<xsl:text> #region Properties </xsl:text>
<xsl:apply-templates select="schema:Property" mode="PropertiesDeclaration">
<xsl:sort select="@Name"/>
</xsl:apply-templates>
<xsl:apply-templates select="schema:NavigationProperty" mode="PropertiesDeclaration">
<xsl:sort select="@Name"/>
</xsl:apply-templates>
<xsl:text> #endregion //Property </xsl:text>
<xsl:text> #region INotifyPropertyChanged Membres
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string property)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(property));
}
}
#endregion </xsl:text>
<xsl:text> } </xsl:text>
<xsl:text> #endregion //class </xsl:text>
</xsl:template>

<xsl:template match="schema:Property" mode="FieldsDeclaration">
<xsl:text> [global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] </xsl:text>
<xsl:text> private</xsl:text>
<xsl:choose>
<xsl:when test="(@Nullable='true') and @Type != 'Edm.String'">
<xsl:text> global::System.Nullable<global::System.</xsl:text>
<xsl:value-of select="substring-after(@Type, '.')"/>
<xsl:text>></xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> global::System.</xsl:text>
<xsl:value-of select="substring-after(@Type, '.')"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text> _</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>; </xsl:text>
</xsl:template>
<xsl:template match="schema:NavigationProperty" mode="FieldsDeclaration">
<xsl:text> [global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] </xsl:text>
<xsl:text> private </xsl:text>
<xsl:variable name="NamespaceName" select="%22%22%22%22%22%22@Namespace%22%3E%3C/xsl:variable%22%22%22%22%22%22%22">../../@Namespace"></xsl:variable>
<xsl:variable name="RelationShipName" select="@Relationship"></xsl:variable>
<xsl:variable name="ValueName" select="@ToRole"></xsl:variable>
<xsl:choose>
<xsl:when test="$Multiplicity = '0..1'">
<xsl:value-of select="substring-after($Type, concat($NamespaceName, '.'))"/>
</xsl:when>
<xsl:when test="$Multiplicity = '1'">
<xsl:value-of select="substring-after($Type, concat($NamespaceName, '.'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>global::System.Collections.ObjectModel.Collection<</xsl:text>
<xsl:value-of select="substring-after($Type, concat($NamespaceName, '.'))"/>
<xsl:text>></xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text> _</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:choose>
<xsl:when test="$Multiplicity = '*'">
<xsl:text> = new global::System.Collections.ObjectModel.Collection<</xsl:text>
<xsl:value-of select="substring-after($Type, concat($NamespaceName, '.'))"/>
<xsl:text>>(); </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>; </xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template match="schema:Property" mode="PropertiesDeclaration">
<xsl:text> public </xsl:text>
<xsl:choose>
<xsl:when test="(@Nullable='true') and @Type != 'Edm.String'">
<xsl:text> global::System.Nullable<global::System.</xsl:text>
<xsl:value-of select="substring-after(@Type, '.')"/>
<xsl:text>></xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> global::System.</xsl:text>
<xsl:value-of select="substring-after(@Type, '.')"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> {</xsl:text>
<xsl:text> get</xsl:text>
<xsl:text> {</xsl:text>
<xsl:text> return this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>;</xsl:text>
<xsl:text> }</xsl:text>
<xsl:text> set</xsl:text>
<xsl:text> {</xsl:text>
<xsl:text> if (this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> != value)</xsl:text>
<xsl:text> {</xsl:text>
<xsl:text> this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> = value;</xsl:text>
<xsl:text> this.OnPropertyChanged("</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>");</xsl:text>
<xsl:text> }</xsl:text>
<xsl:text> }</xsl:text>
<xsl:text> } </xsl:text>
</xsl:template>
<xsl:template match="schema:NavigationProperty" mode="PropertiesDeclaration">
<xsl:text> [global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
public </xsl:text>
<xsl:variable name="NamespaceName" select="%22%22%22%22%22%22@Namespace%22%3E%3C/xsl:variable%22%22%22%22%22%22%22">../../@Namespace"></xsl:variable>
<xsl:variable name="RelationShipName" select="@Relationship"></xsl:variable>
<xsl:variable name="ValueName" select="@ToRole"></xsl:variable>
<xsl:choose>
<xsl:when test="$Multiplicity = '0..1'">
<xsl:value-of select="substring-after($Type, concat($NamespaceName, '.'))"/>
</xsl:when>
<xsl:when test="$Multiplicity = '1'">
<xsl:value-of select="substring-after($Type, concat($NamespaceName, '.'))"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>global::System.Collections.ObjectModel.Collection<</xsl:text>
<xsl:value-of select="substring-after($Type, concat($NamespaceName, '.'))"/>
<xsl:text>></xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> {</xsl:text>
<xsl:text> get</xsl:text>
<xsl:text> {</xsl:text>
<xsl:text> return this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>;</xsl:text>
<xsl:text> }</xsl:text>
<xsl:text> set</xsl:text>
<xsl:text> {</xsl:text>
<xsl:text> if (this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> != value)</xsl:text>
<xsl:text> {</xsl:text>
<xsl:text> this._</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text> = value;</xsl:text>
<xsl:text> this.OnPropertyChanged("</xsl:text>
<xsl:value-of select="@Name"/>
<xsl:text>");</xsl:text>
<xsl:text> }</xsl:text>
<xsl:text> }</xsl:text>
<xsl:text> } </xsl:text>
</xsl:template>
<xsl:template match="edmx:Classes">
<xsl:text> public sealed class ClassNames { </xsl:text>
<xsl:for-each select="edmx:Class">
<xsl:text> public const string </xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text> = "</xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text>"; </xsl:text>
</xsl:for-each>
<xsl:text> } </xsl:text>
</xsl:template>
<xsl:template match="edmx:Class" mode="AttributesDeclaration">
<xsl:text>namespace ANPE.Annuaire.ReglesMetier.</xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text>s { </xsl:text>
<xsl:text> public sealed class </xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text>Attributes { </xsl:text>
<xsl:for-each select="edmx:Attributes/edmx:add">
<xsl:text> ///<summary> </xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text></summary> </xsl:text>
<xsl:text> public const string </xsl:text>
<xsl:value-of select="@Name" />
<xsl:text> = "</xsl:text>
<xsl:value-of select="@Name" />
<xsl:text>"; </xsl:text>
<xsl:if test="@MinLength">
<xsl:text> public const int </xsl:text>
<xsl:value-of select="@Name" />
<xsl:text>_MinLength = </xsl:text>
<xsl:value-of select="@MinLength" />
<xsl:text>; </xsl:text>
</xsl:if>
<xsl:if test="@MaxLength">
<xsl:text> public const int </xsl:text>
<xsl:value-of select="@Name" />
<xsl:text>_MaxLength = </xsl:text>
<xsl:value-of select="@MaxLength" />
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text> } </xsl:text>
<xsl:text>} </xsl:text>
</xsl:template>
<xsl:template match="edmx:Class" mode="ClassesDeclaration">
<xsl:text>namespace ANPE.Annuaire.ReglesMetier.</xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text>s { </xsl:text>
<xsl:text> [Serializable]</xsl:text>
<xsl:text> [DirectoryClass(ClassNames.</xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text>)]</xsl:text>
<xsl:text> public partial class </xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text> : System.ICloneable { </xsl:text>

<xsl:for-each select="edmx:Attributes/edmx:add">
<xsl:text> private </xsl:text>
<xsl:choose>
<xsl:when test="@IsSingleValued='false'">
<xsl:choose>
<xsl:when test="contains(@DataType,',')">
<xsl:value-of select="substring-before(@DataType,',')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@DataType" />
</xsl:otherwise>
</xsl:choose>
<xsl:text>[]</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="contains(@DataType,',')">
<xsl:value-of select="substring-before(@DataType,',')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@DataType" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
<xsl:text> _</xsl:text>
<xsl:value-of select="@Name" />
<xsl:text>; </xsl:text>
</xsl:for-each>
<xsl:text> </xsl:text>

<xsl:for-each select="edmx:Attributes/edmx:add">
<xsl:text> [DirectoryAttribute(</xsl:text>
<xsl:value-of select="%22%22%22%22%22%22@LogicalName%22%22%22%22%22%22%22">../../@LogicalName" />
<xsl:text>Attributes.</xsl:text>
<xsl:value-of select="@Name" />
<xsl:text>)] </xsl:text>
<xsl:text> public </xsl:text>
<xsl:choose>
<xsl:when test="@IsSingleValued='false'">
<xsl:choose>
<xsl:when test="contains(@DataType,',')">
<xsl:value-of select="substring-before(@DataType,',')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@DataType" />
</xsl:otherwise>
</xsl:choose>
<xsl:text>[]</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="contains(@DataType,',')">
<xsl:value-of select="substring-before(@DataType,',')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@DataType" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
<xsl:value-of select="@LogicalName" />
<xsl:text> </xsl:text>
<xsl:text> { </xsl:text>
<xsl:text> get { return _</xsl:text>
<xsl:value-of select="@Name" />
<xsl:text>; } </xsl:text>
<xsl:text> set { _</xsl:text>
<xsl:value-of select="@Name" />
<xsl:text>= value; } </xsl:text>
<xsl:text> } </xsl:text>
</xsl:for-each>
<xsl:text> public Object Clone() </xsl:text>
<xsl:text> { </xsl:text>
<xsl:text> return MemberwiseClone (); </xsl:text>
<xsl:text> } </xsl:text>
<xsl:text> } </xsl:text>
<xsl:text>} </xsl:text>
</xsl:template>
<xsl:template match="edmx:Queries">
<xsl:text> public class QueryNames { </xsl:text>
<xsl:for-each select="edmx:Query">
<xsl:text> public const string </xsl:text>
<xsl:value-of select="@Name" />
<xsl:text> = "</xsl:text>
<xsl:value-of select="@Name" />
<xsl:text>"; </xsl:text>
</xsl:for-each>
<xsl:text> } </xsl:text>
</xsl:template>
</xsl:stylesheet>

Even if you know absolutly nothing about xslt language you can read this file.You can find here all templates that match the nodes of the $metadata result of the web data service. You can change it very easlily.

Inside the properties of the client project select the generation event. Inside the pre build event you can see the following command :

$(SolutionDir)Tools\msxsl.exe http://localhost:3932/BackOfficeServices/WebDataService.svc/$metadata $(ProjectDir)EntitiesGeneratorXSLTFile.xslt -o $(ProjectDir)EntitiesCustom.cs

it call the msxsl.exe tool in order to generate a file named entitiescustom.cs from the transformation of our service with a specified xslt file. Each time you build the solution, the EntitiesCustom.cs file will be generated bu the msxsl.exe tool with the xml extracted from the $metadata response of the web data service and with the xslt seen before. You can begin this command with the "REM" keyword in order to comment the line.

The result (proxy classes)

The result if similar to the proxy class generated by Microsoft. I added some debugger attributes to clean the class aspect and some #region. Here is one of the entity class generated :

Collapse
#region class Course










[global::System.Serializable()]
[global::System.Data.Services.Common.DataServiceKeyAttribute("CourseID")]
public partial class Course : global::System.ComponentModel.INotifyPropertyChanged
{
#region Fields
[global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private global::System.Int32 _CourseID;
[global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private global::System.Int32 _Credits;
[global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private global::System.String _Title;
[global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private global::System.Collections.ObjectModel.Collection<CourseGrade> _CourseGrade =
new global::System.Collections.ObjectModel.Collection<CourseGrade>();
[global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private Department _Department;
[global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private OnlineCourse _OnlineCourse;
[global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private OnsiteCourse _OnsiteCourse;
[global::System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private global::System.Collections.ObjectModel.Collection<Person> _Person =
new global::System.Collections.ObjectModel.Collection<Person>();
#endregion //Fields
#region Properties
public global::System.Int32 CourseID
{
get
{
return this._CourseID;
}
set
{
if (this._CourseID != value)
{
this._CourseID = value;
this.OnPropertyChanged("CourseID");
}
}
}
public global::System.Int32 Credits
{
get
{
return this._Credits;
}
set
{
if (this._Credits != value)
{
this._Credits = value;
this.OnPropertyChanged("Credits");
}
}
}
public global::System.String Title
{
get
{
return this._Title;
}
set
{
if (this._Title != value)
{
this._Title = value;
this.OnPropertyChanged("Title");
}
}
}
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
public global::System.Collections.ObjectModel.Collection<CourseGrade> CourseGrade
{
get
{
return this._CourseGrade;
}
set
{
if (this._CourseGrade != value)
{
this._CourseGrade = value;
this.OnPropertyChanged("CourseGrade");
}
}
}
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
public Department Department
{
get
{
return this._Department;
}
set
{
if (this._Department != value)
{
this._Department = value;
this.OnPropertyChanged("Department");
}
}
}
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
public OnlineCourse OnlineCourse
{
get
{
return this._OnlineCourse;
}
set
{
if (this._OnlineCourse != value)
{
this._OnlineCourse = value;
this.OnPropertyChanged("OnlineCourse");
}
}
}
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
public OnsiteCourse OnsiteCourse
{
get
{
return this._OnsiteCourse;
}
set
{
if (this._OnsiteCourse != value)
{
this._OnsiteCourse = value;
this.OnPropertyChanged("OnsiteCourse");
}
}
}
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
public global::System.Collections.ObjectModel.Collection<Person> Person
{
get
{
return this._Person;
}
set
{
if (this._Person != value)
{
this._Person = value;
this.OnPropertyChanged("Person");
}
}
}
#endregion //Property
#region INotifyPropertyChanged Membres
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string property)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(property));
}
}
#endregion
}
#endregion //class

now we can test our proxy.

The test

We will try to retrieve a Person and change its name.

Here is the code added to the Program.cs file of the client side project.

Collapse
var query = from u in entities.Person
where u.LastName == "Abercrombie"
select u;

foreach (Person person in query)
{
Console.Out.WriteLine("A Person finded :");
Console.Out.WriteLine(string.Format("{0} {1}", person.FirstName, person.LastName));

Console.Out.WriteLine("Why not changing its name ?");
Console.Out.WriteLine("Please specifies a new first name :");
string firstName = Console.In.ReadLine();

person.FirstName = firstName;
entities.UpdateObject(person);
entities.SaveChanges();
Console.Out.WriteLine("New name saved");
}

gd06.png

Our proxy class works well !

Conclusion

With this way of doing you can easily add features to your entities classes and enjoy the ADO.Net data services. Just change the xslt and add your own features.

I did not test the xslt in a lot of scenarii. If there are some problem just ask me.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

->Read More...