Dynamically compare 2 entity property values in VB.net

Had a scenario today where we had to compare the property values of view model against a domain entity, so I wrote simple windows client sample to dynamically compare properties with the same name to dynamically compare values and if the values are different just add the names of these properties to a list

On Load I create 2 entities _person and _student; person has name and age properties; _student has name, age, sex and school. On comparing _person and _student we find “name” property values differ, age is same, sex and school does not apply to person class. So the only property I want in difference list is “name”

Code Snippet
  1. Public Class Form1
  2.     Private _person As Person
  3.     Private _student As Student
  4.     Private Sub Compare_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Compare.Click
  5.         Dim diffList As New List(Of String)
  6.         For Each personProp In _person.GetType.GetProperties
  7.             Dim studentValue = _student.GetType.GetProperty(personProp.Name).GetValue(_student, Nothing)
  8.             Dim personValue = _person.GetType.GetProperty(personProp.Name).GetValue(_person, Nothing)
  9.             If studentValue <> personValue Then
  10.                 diffList.Add(personProp.Name)
  11.             End If
  12.         Next
  13.     End Sub
  14.     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  15.         _person = New Person With {.name = “A”, .age = 10}
  16.         _student = New Student With {.name = “B”, .age = 10, .sex = “m”, .school = “XYZ”}
  17.     End Sub
  18. End Class
Advertisements

Concurrency in Entity Framework 4.1 code first.

Let us assume we have a person entity and it looks as below

Imports System.ComponentModel.DataAnnotations
Public Class Person

    Public Property ID As Integer
    <StringLength(50)>
    Public Property FirstName As String
    <Timestamp()>
    Public Property RowVersion As Byte()

End Class

Using EF 4.1 and code first, a typical update would look as show below

       Using entities = New EFConcurrencyTestContext
            Try
                Dim personEntity = entities.People.Where(Function(p) p.ID = 1).FirstOrDefault
                personEntity.FirstName = "CCC"
                entities.SaveChanges()
            Catch concurrencyException As DbUpdateConcurrencyException
                Throw New Exception("The record u r trying to update has changed")
            Catch ex As Exception
                Throw New Exception("Some Exception")

            End Try
        End Using
Since our main focus is to test Concurrency, let put a break point at the line Highlighted, start debugging when the debugger stops at personEntity.FirstName = "CCC", in the database update the person firstname, then continue debugging, on the savechanges you would get a DbUpdateConcurrencyException. This is pretty straight forward and works as expected. Let’s take a different scenario, for e.g. in multi tier MVC application

1.    In the service layer I would do get person, say the person FirstName is ‘A’, RowVersion is 1
2.    I would then build a ViewModel, take only a few data elements from person entity I need for the viewModel, I don’t transfer the person entity across tiers, meaning my controller only know about my viewmodel and is unaware of my domain object which is person. In order to check for Concurrency I will create a property in my ViewModel called PersonRowVersion and store the rowversion in it.
3.    As the data is being manipulated by my view, let us assume the record in the database was updated as well.  Say FirstName in the Database is ‘B’ and RowVersion is 2
4.    Now my View modified the person FirstName to ‘C’, I had stored my RowVersion either using a hidden field or in the Tempdata. I build the ViewModel, take the modified FirstName which is ‘C’ and restore the RowVersion from my hidden field which is 1
5.    In the service layer, I get the person entity from the database, which will have the FirstName = ‘B” and RowVersion = “2”. I update the FirstName to “C” and RowVersion to “1” and do Context.Savechanges. The update happens but no concurrency exception is raised
6.    In order to get the Concurrency Exception you will have to modify the OriginalValue of the property that is used for tracking concurrency, in my case it is RowVersion. Something like this

entities.Entry(personEntity).Property("RowVersion").OriginalValue = _rowVersion

I have created a few test cases (Windows client application) to mimic this process. The idea is to show what works and what does not.

Imports System.Data.Entity.Infrastructure

Public Class Form1

    Private _fName As String
    Private _rowVersion As Byte()
    Private _person As Person

    Private Sub CreateDB_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CreateDB.Click
        Using entities = New EFConcurrencyTestContext
            Dim personEntity As New Person With {.FirstName = "AAA"}
            entities.People.Add(personEntity)
            entities.SaveChanges()
        End Using
    End Sub

    Private Sub Get1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Get1.Click
        Using entities = New EFConcurrencyTestContext
            Dim personEntity = entities.People.Where(Function(p) p.ID = 1).FirstOrDefault
            _fName = personEntity.FirstName
            _rowVersion = personEntity.RowVersion
            _person = personEntity
        End Using
    End Sub

    Private Sub TestConcurrencyWrongWayButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TestConcurrencyWrongWayButton.Click
        Using entities = New EFConcurrencyTestContext
            Try
                Dim personEntity = entities.People.Where(Function(p) p.ID = 1).FirstOrDefault
                personEntity.FirstName = "CCC"
                personEntity.RowVersion = _rowVersion
                entities.SaveChanges()
            Catch concurrencyException As DbUpdateConcurrencyException
                Throw New Exception("The record u r trying to update has changed")
            Catch ex As Exception
                Throw New Exception("Some Exception")

            End Try

        End Using
    End Sub

    Private Sub TestConcurrencyRightWayButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TestConcurrencyRightWayButton.Click
        Using entities = New EFConcurrencyTestContext
            Try
                Dim personEntity = entities.People.Where(Function(p) p.ID = 1).FirstOrDefault
                personEntity.FirstName = "CCC"
                entities.Entry(personEntity).Property("RowVersion").OriginalValue = _rowVersion
                entities.SaveChanges()
            Catch concurrencyException As DbUpdateConcurrencyException
                Throw New Exception("The record u r trying to update has changed")
            Catch ex As Exception
                Throw New Exception("Some Exception")
            End Try

        End Using
    End Sub

    Private Sub TestConcurrencyWithAttachButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TestConcurrencyWithAttachButton.Click
        Using entities = New EFConcurrencyTestContext
            Try
                _person.FirstName = "xxxx"
               entities.Entry(_person).State = EntityState.Modified
                entities.SaveChanges()
            Catch concurrencyException As DbUpdateConcurrencyException
                Throw New Exception("The record u r trying to update has changed")
            Catch ex As Exception
                Throw New Exception("Some Exception")
            End Try
        End Using
    End Sub

    Private Sub ModifiedRepositoryWithOriginalRowVersionButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ModifiedRepositoryWithOriginalRowVersionButton.Click
        Dim _repository As New TestRepository(New EFConcurrencyTestContext)
        Try
            Dim personEntity = _repository.GetQuery(Of Person).Where(Function(p) p.ID = 1).FirstOrDefault
            personEntity.FirstName = "CCC"
           _repository.SetRowVersion(Of Person)(personEntity, _rowVersion)
            _repository.Save()
        Catch concurrencyException As DbUpdateConcurrencyException
            Throw New Exception("The record u r trying to update has changed")
        Catch ex As Exception
            Throw New Exception("Some Exception")

        End Try
    End Sub
End Class

image

Test Case 1
1.    Click Get 1 – Person data is got from the database and stored in memory
       a.    Person.FirstName = A
       b.    Person.RowVersion = 1
2.    Update the Person Table FirstName = B, the row version will be 2
3.    Click TestConcurrencyWorngWay, Update happens no concurrency exception

Test Case 2
Repeat 1 and 2 as in Test Case1, Click TestConcurrencyRightWay. No Update, concurrency exception is raised

Test Case 3

You can also get the concurrency exception to work by doing attach, but you got to store the person entity in memory to attach it to the context. In multi tier MVC application if you are using View model to carry data to the controller, then this becomes a problem as you need to store the domain object in memory. But to test it repeat 1 and 2 as in test case 1 and then click TestConcurrencyWith Attach, no update happens concurrency exception occurs

Test Case 4

Sometime you may be using repository pattern in your application, to test this repeat 1 and 2 as in test case 1, and then click ModifiedRepositoryWithOriginalRowVersion. Below is a sample repository

Imports System.Data.Entity
Imports System.Data.Entity.Design.PluralizationServices
Imports System.Globalization
Imports System.Data.Entity.Infrastructure

Public Class TestRepository
    Private _context As DbContext
    Private ReadOnly _pluralizer As PluralizationService = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en"))
    Public Sub New(ByVal context As DbContext)
        If context Is Nothing Then
            Throw New ArgumentNullException("context")
        End If
        Me._context = context
    End Sub

    Private Function GetEntityName(Of TEntity As Class)() As String
        Return String.Format("{0}.{1}", DirectCast(_context, IObjectContextAdapter).ObjectContext.DefaultContainerName, _pluralizer.Pluralize(GetType(TEntity).Name))
    End Function

    Public Sub Save()
        _context.SaveChanges()
    End Sub

    Public Sub SetRowVersion(Of TEntity As Class)(ByVal entity As TEntity, ByVal originalRowVersion As Byte())
       _context.Entry(entity).Property("RowVersion").OriginalValue = originalRowVersion
    End Sub

    Public Function GetQuery(Of TEntity As Class)() As IQueryable(Of TEntity)
        Dim entityName = GetEntityName(Of TEntity)()
        Return DirectCast(_context, IObjectContextAdapter).ObjectContext.CreateQuery(Of TEntity)(entityName)
    End Function
End Class

Wire IIS7 Basic Authentication to Authenticate against custom provider

The best custom basic authentication out there is at http://custombasicauth.codeplex.com/

But many people have told me that they don’t want to write iis extensions modules etc. So here is the simplest one, just implement ihttpmodlue

1.    Create a class library project called it Company.HttpModules
2.    I add the a class called RevBasicAuthenticationModule
3.    Below is the Code for the class

Imports System.Web
Imports System.Security.Principal
Imports System.Text

Public Class RevBasicAuthenticationModule
Implements IHttpModule

Public Sub Dispose() Implements System.Web.IHttpModule.Dispose

End Sub

Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
AddHandler context.AuthenticateRequest, AddressOf OnEnter
End Sub

Private Sub OnEnter(ByVal sender As Object, ByVal e As EventArgs)
Dim application As HttpApplication = DirectCast(sender, HttpApplication)
If Not Authenticate(application.Context) Then
application.Context.Response.Status = “401 Unauthorized”
application.Context.Response.StatusCode = 401
application.Context.Response.AddHeader(“WWW-Authenticate”, “Basic realm=My Company”)
application.CompleteRequest()
End If
End Sub

Public Shared Function Authenticate(ByVal context As HttpContext) As Boolean
‘Enable this if you are using ssl. Which you should
‘If Not HttpContext.Current.Request.IsSecureConnection Then
‘    Return False
‘End If

If Not HttpContext.Current.Request.Headers.AllKeys.Contains(“Authorization”) Then
Return False
End If

Dim authorizationHeader As String = HttpContext.Current.Request.Headers(“Authorization”)

Dim principal As IPrincipal = Nothing
If GetPrincipal(authorizationHeader, principal) Then
HttpContext.Current.User = principal
Return True
End If
Return False
End Function

Private Shared Function GetPrincipal(ByVal authorizationHeader As String, ByVal principal As IPrincipal) As Boolean
Dim credentials = GetAuthorizationHeader(authorizationHeader)
If credentials IsNot Nothing AndAlso ValidateUser(credentials, principal) Then
Return True
End If

principal = Nothing
Return False
End Function

Private Shared Function GetAuthorizationHeader(ByVal authorizationHeaderInfo As String) As String()
‘Get Header info.
If authorizationHeaderInfo Is Nothing OrElse authorizationHeaderInfo.Length = 0 OrElse Not authorizationHeaderInfo.StartsWith(“Basic”) Then
Return Nothing
End If

‘ The Credentials are seperated by ‘:’ and are Base64 encoded
Dim EncodedCredentials As String = authorizationHeaderInfo.Substring(6)
Dim credentials As String() = Encoding.ASCII.GetString(Convert.FromBase64String(EncodedCredentials)).Split(New Char() {“:”c})

If credentials.Length <> 2 OrElse String.IsNullOrEmpty(credentials(0)) OrElse String.IsNullOrEmpty(credentials(0)) Then
Return Nothing
End If

Return credentials
End Function

Private Shared Function ValidateUser(ByVal creds As String(), ByVal principal As IPrincipal) As Boolean
If creds(0) = “Rev” AndAlso creds(1) = “Rev” Then
principal = New GenericPrincipal(New GenericIdentity(“Rev”), New String() {“Administrator”, “User”})
Return True
ElseIf creds(0) = “Ram” AndAlso creds(1) = “Ram” Then
principal = New GenericPrincipal(New GenericIdentity(“Ram”), New String() {“User”})
Return True
Else
principal = Nothing
Return False
End If
End Function

End Class

4.    Added a empty asp.net website to the solution

5.    Add reference to the Company.httpModules

6.    Edit web.config

<system.webServer>
<modules>
<add name=”Company.httpModules” type=”Company.httpModules.RevBasicAuthenticationModule”/>
</modules>
<security>
<authorization>
<add accessType=”Allow” users=”” roles=””/>
</authorization>
</security>-
</system.webServer>

7.    Important make sure Anonymous Authentication is enabled and the rest are disabled for that application

image

8.    That is it you have a successful custom basic authentication. You can implement your own validate user how you want.
9.    But remember the authentication will take place for every request. So you have to use a mechanism to create a token or  cache credentials
10.    In the Custom Basic Authentication code on codeplex created by Dominick Baier has a cache mechanism which is good and can be used here

Custom Basic Authentication for IIS7

Installing and Using Custom Basic Authentication for IIS7.
1.    Download the code from http://custombasicauth.codeplex.com/.
2.    Open visual studio command prompt by right clicking run as administrator.
3.    Cd to the folder where you unzipped the downloaded source.
4.    In the output folder there is Install command file. Edit this file in notepad.
5.    Remove “rem” from line 16 rem iisschema.exe /install CustomBasicAuthentication_schema.xml.
6.    Remove “rem” from line 20 i.e rem IisRegMgmt CustomBasicAuth LeastPrivilege.CustomBasicAuthentication.Management.CustomBasicAuthenticationModuleProvider LeastPrivilege.CustomBasicAuthentication.Management.dll
7.    Save the file
8.    Run Install.cmd from VS cmd prompt

What happens when you run the install.cmd
1.    The 3 dlls will be added to the GAC
2.    When the command “iisschema.exe /install CustomBasicAuthentication_schema.xml” is executed 2 things happen.
•    CustomBasicAuthentication_schema will be copied to C:\Windows\System32\inetsrv\config\schema folder
•    <section name=”customBasicAuthentication” overrideModeDefault=”Allow” allowDefinition=”Everywhere” /> will be added to
<sectionGroup name=”system.webServer”>
<sectionGroup name=”security”>
<sectionGroup name=”authentication”>
Section in applicationHost.config file
3.    When IisRegMgmt is run it edit administration.config file.
a.    <add name=”CustomBasicAuth” type=”LeastPrivilege.CustomBasicAuthentication.Management.CustomBasicAuthenticationModuleProvider, LeastPrivilege.CustomBasicAuthentication.Management, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f20dc168dfd54966″ />  to the  </moduleProviders>

b.    To    <location path=”.”><modules><add name=”CustomBasicAuth” /></modules>

4.    Open an application in inetmgr. Double click Authentication

image

5.    You should see Custom Basic Authentication

How to use it

1.    Create an empty asp.net website.
2.    Edit web.config, Add
<system.webServer>
<validation validateIntegratedModeConfiguration=”false”/>
<modules>
<remove name=”ScriptModule”/>
<add name=”ScriptModule” preCondition=”managedHandler” type=”System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>
<add name=”CustomBasicAuthentication” type=”LeastPrivilege.CustomBasicAuthentication.CustomBasicAuthenticationModule, LeastPrivilege.CustomBasicAuthenticationModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=F20DC168DFD54966″/>
</modules>
To System.webserver,modules section
3.    Add
<security>
<authentication>
<customBasicAuthentication enabled=”true” realm=”Your Company Name” providerName=”default” cachingEnabled=”true” cachingDuration=”15″ requireSSL=”false”/>
</authentication>
</security>
</system.webServer>
4.    You will need to hook up your custom provider. To Test I created a class library project. Called Company.Security.Provider. Added a class calledMemberProvider.vb
5.    Add refrence to system.web
6.    In the class Imports System.Web
7.    And Inherits System.Web.Security.MembershipProvider

image

8.    The only method I implement was ValidateUser
Public Overrides Function ValidateUser(ByVal username As String, ByVal password As String) As Boolean
If username = “rev” And password = “rev” Then
Return True
Else
Return False
End If
End Function
9.    Here I intend to hook up to my active directory module
10.    In the web project add reference to this class library.
11.    Edit the web.config file, add the default  provider in system.web section

<system.web>
<membership defaultProvider=”Company.Security.Provider”>
<providers>
<clear/>
<add name=”Company.Security.Provider” type=”Company.Security.Provider.MemberProvider”/>
</providers>
</membership>

12.    That’s it, you have custom basic authentication working

Accessing File Resource on a UNC share from IIS7 running .Net 4.0 win 2008

Today we had a situation where a page was trying to load a string from another file in the UNC share.

The asp.net page looked like this

<%@ Page EnableSessionState=”False”%>

 <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”  “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“>

 <html xmlns=”http://www.w3.org/1999/xhtml”&gt;

<head runat=”server”>

    <title></title>

</head>

<body>

    <form runat=”server”>

<div>

                 <asp:PlaceHolder runat=”server” Visible=”true”>

                    <%Response.WriteFile(“/Common/breadcrumb.htm”)%>

                </asp:PlaceHolder>

            </div>

    <div>

    My Test Page

    </div><asp:Literal runat=”server”></asp:Literal>

    <asp:Button runat=”server” Text=”test”/>

    </form>

</body>

</html>

Breadcrum.htm file just as a string. When this is executed on IIS7 in Asp.Net v2 works fine. But when run 0n IIS7 and Asp.Net v4 this generates System.UnauthorizedAccessException: Access to the path “\\unshare\common\breadcrumb.htm” is denied

Fix

<%@ Page EnableSessionState=”False”%>

<%@ Import Namespace=”System.IO” %>

<%@ Import Namespace=”System.Security.Permissions” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<script runat=”server”>

    Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)

        Dim oFp As FileIOPermission = New  _

        FileIOPermission(FileIOPermissionAccess.Read, Server.MapPath(“/Common/breadcrumb.htm”))

        oFp.Assert()

        Dim data As String = File.ReadAllText(Server.MapPath(“/Common/breadcrumb.htm”))

        Literal1.Text = data

    End Sub

</script>

<html xmlns=”http://www.w3.org/1999/xhtml”&gt;

<head runat=”server”>

    <title></title>

</head>

<body>

    <form runat=”server”>

    <div>

    My Test Page

    </div><asp:Literal runat=”server”></asp:Literal>

 <asp:Button ID=”Button1″ runat=”server” Text=”test” OnClick=”Button1_Click”/>

    </form>

</body>

</html>

My application pool was running under Network Services. I could have either changed the identity of the pool to use a user that had access to unc share or I could just programmatically give permission to file.  I used the FileIOPermission to grant access to the file and then read it.

WCF In Action

1.    Create a blank solution

image

2.    Add new class library project to the solution
image
3.    Rename Class1.vb as IPerson.vb, edit the file, and change class to an interface

Public Interface IPerson

End Interface

4.    To WcfIn3Tiers.Service.Contracts add reference to System.ServiceModel
image

5.    Change IPerson file to look like below

Imports System.ServiceModel
<ServiceContract()> _
Public Interface IPerson

End Interface

6.    Add new class library project WcfIn3Tiers.Entities to the solution
image

7.    Rename Class1 to Person.
8.    To WcfIn3Tiers.Entities add reference to System.Runtime.Serialization
9.    Edit person class to look like below

Imports System.Runtime.Serialization
<DataContract()> _
Public Class Person
<DataMember()> _
Public personId As String
<DataMember()> _
Public firstName As String
<DataMember()> _
Public lastName As String
End Class

10.    To WcfIn3Tiers.Service.Contracts add reference to WcfIn3Tiers.Entities project
image

11.    Edit IPerson, the code should like shown below

Imports System.ServiceModel
Imports WcfIn3Tiers.Entities
<ServiceContract()> _
Public Interface IPerson
<OperationContract()> _
Sub addPerson(ByVal personEntity As Person)
<OperationContract()> _
Function getPeople() As List(Of Person)
<OperationContract()> _
Sub removePerson(ByVal pId As String)
End Interface
12.    Add a new class library WcfIn3Tiers.Service
image

13.    To this project add reference to System.ServiceModel, WcfIn3Tiers.Entities, WcfIn3Tiers.Service.Contracts
14.    Rename Class1 to PersonService and edit it to look like below
Imports WcfIn3Tiers.Entities
Imports WcfIn3Tiers.Service.Contracts
Imports System.ServiceModel
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.Single)> _
Public Class PersonService
Implements IPerson

Private _listOfPeople As New List(Of Person)

Public Sub addPerson(ByVal personEntity As Entities.Person) Implements Contracts.IPerson.addPerson
personEntity.personId = Guid.NewGuid.ToString
_listOfPeople.Add(personEntity)
End Sub
Public Function getPeople() As System.Collections.Generic.List(Of Entities.Person) Implements Contracts.IPerson.getPeople
Return _listOfPeople
End Function

Public Sub removePerson(ByVal pId As String) Implements Contracts.IPerson.removePerson
_listOfPeople.Remove(_listOfPeople.Find(Function(e) e.personId.Equals(pId)))
End Sub
End Class
15.    Now we have defined the service contract, data contract and the service. Which in the remoting world we used to call Interface. Entities and Core.

Hosting this Service in a Console Application
16.    Add a console application to the solution call it WcfIn3Tiers.ConsoleHost
image

17.    To WcfIn3Tiers.ConsoleHost add reference to WcfIn3Tiers.Service project and System.ServiceModel
18.    Edit model1.vb file to look like below

Imports WcfIn3Tiers.Service
Imports System.ServiceModel
Module Module1

Sub Main()
Dim myWcfHost As ServiceHost = New ServiceHost(GetType(PersonService))
myWcfHost.Open()
Console.WriteLine(“Service is up and running…………”)
Console.ReadLine()
myWcfHost.Close()
End Sub

End Module

19.    Build the solution
20.    Configure the end points
21.    Add new item in general section pick app.config

22.    App.config file contains some extras which we will not need just delete the <system.diagnostics> tag
23.    Right click app.config file and select open with .. if you have not already associated SvcConfigEditor.exe to open with, click add
image

24.    Click browse
25.    Browse to C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\ SvcConfigEditor.exe
26.    In Win7 I found it here “C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\SvcConfigEditor.exe”
27.    Friendly Name: WCF Configuration Editor

image

image

28.    Click OK
image
29.    Click Create a New Service
image
30.    Browse to bin\debug folder in the console application and select WcfIn3Tiers.service.dll.

image
31.    Then Select WcfIn3Tiers.Service.PersonService click open
image

32.    Click Next
image
33.    Click Next
image
34.    Click Next
image
35.    Next
image

36.    In the address type basic this a relative address. We will add the base address later
37.    Click on the Host and in the base Address section click new
image
38.    Click on
39.    Open the Endpoints, we have the basicHttpBinding we configured earlier. Let us now configure the metadata endpoint
40.    Open Advanced—> Service Behaviors
image
41.    Click New Service Behavior Configuration
image
42.    Click Add
image
43.    Select serviceMetadata
44.    Now select the actual service right on the top and configure the behavior
image
45.    Click  in the behaviorConfiguration dropdown and select NewBehavior
46.    Configure the metadata endpoint
47.    Right click Endpoints and select New Service Endpoints
image

48.    For the Contract click on the browse .. button
image

49.    Click GAC and select System.ServiceModel click open
image

50.    Select IMetadataExchange
51.    Close the editor save the changes
52.    The app.config will look like below
<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>

<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name=”NewBehavior”>
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration=”NewBehavior” name=”WcfIn3Tiers.Service.PersonService”>
<endpoint address=”basic” binding=”basicHttpBinding” bindingConfiguration=””
contract=”WcfIn3Tiers.Service.Contracts.IPerson” />
<endpoint address=”mex” binding=”mexHttpBinding” bindingConfiguration=””
contract=”IMetadataExchange” />
<host>
<baseAddresses>
<add baseAddress=”http://localhost:8899/WcfIn3Tiers” />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

53.    Set WcfIn3Tiers.ConsoleHost as startup project and run the solution
image

54.    To test service
55.    Open VS command prompt, type in
wcftestclient http://localhost:8899/WcfIn3Tiers
56.    The test client opens up and display service for testing
image
57.    Double click on addPerson, punch in the firstName and lastName and click Invoke
image
58.    You will get a null response
59.    To test getPeople double click it and hot invoke
image
60.    You should see person you just added
61.    To test removePerson copy the PersonId from getPerson and punch it into the value column and hit invoke
image
62.    This concludes testing the service

Hosting the service in IIS
63.    We will create a new folder in C:\Temp\WcfIn3Tiers call it web
image
64.    Create new Virtual directory call it WcfIn3TierSite and map it C:\Temp\WcfIn3Tiers\Web
image

image
65.    Finish
66.    Add a new website project to the solution, select WCF Service
image

67.    Location HTTP and point to the newly created VD
68.    When the new project is created, under the app_code you will have 2 file IService.vb and Service.Vb, we will not need them just delete.
69.    Add reference to WcfIn3Tier.Service project
70.    The important file we will be working on is Service.svc file, double click it. The file will have code as shown below
<%@ ServiceHost Language=”VB” Debug=”true” Service=”Service” CodeBehind=”~/App_Code/Service.vb” %>
71.    Modify it to look like below
<%@ ServiceHost Language=”VB” Debug=”true” Service=”WcfIn3Tiers.Service.PersonService” %>
72.    Open the web.config with WCF Configuration Editor as we did earlier
image

73.    Click on the service and change the service name by click on the browse button
image

74.    In the bin directory select WcfIn3Tiers.Service.dll, then select the PersonService
image
75.    Click open
76.    Don’t worry about the Host. We will configure the end point. This project template already come configured with 2 endpoints we will just reuse them, but point to our person service contract
77.    Click on the 1st end point, in the address textbox add ws as the relative address. Then click on the contract textbox’s browse button
image
78.    Change the contact to IPerson by browsing to WcfIn3Tiers.Service.Contracts.dll
image
79.    Click Open, select WcfIn3Tiers.service.Contracts.IPerson
image
80.    We will leave mex endpoint as it is
81.    Save the file and exit
82.    To Test this, point the browser url to http://localhost/WcfIn3TierSite/Service.svc
image
83.    This is give WSDL url and how you can consume the service
84.    Open the WCFTestClient and point to the wsdl
image

85.    You will again see the familiar test client interface, go ahead and test the service as mentioned earlier

Creating a client to consume the service
86.    Add a new window forms application project to the solution
image

87.    Add Service reference
88.    Point to wsdl file for the service we just hosted in iis, click go, put MyPersonWebService in the Namespace textbox
image
89.    Vs will create all the proxy classes need
90.    Create a couple of textboxs and button as shown
image
91.    In the code behind

Imports WcfIn3Tiers.Client.MyPersonWebService
Public Class Form1
Private client As PersonClient
Private Sub AddButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddButton.Click
Dim p As New Person
p.FirstName = FnTextBox.Text
p.LastName = LnTextBox.Text
client.addPerson(p)
End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
client.Close()
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
client = New PersonClient()
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim ps As Person()
ps = client.getPeople()
DataGridView1.DataSource = ps
End Sub
End Class

92.    Set your client project as startup and test it out

VS2010 (.net framework 4.0) and XP SP3 Compile Error

When you compile the application you get

Error 5 The “GenerateResource” task failed unexpectedly.

System.DllNotFoundException: Unable to load DLL ‘FileTracker.dll’: A dynamic link library (DLL) initialization routine failed. (Exception from HRESULT: 0x8007045A)

Workaround

In C:\WINDOWS\Microsoft.NET\Framework\v4.0.30128 locate Microsoft.Common.targets open in notepad. Locate <GenerateResource tag, remove the attributes TrackFileAccess=”$(TrackFileAccess)” TrackerLogDirectory=”$(TrackerLogDirectory)”, save the file, Close and Re Open Visual Studio