DCSIMG
January 2008 - Posts - Gady Elkarif's Blog

Gady Elkarif's Blog

January 2008 - Posts

WCF Services and AJAX

WCF Services and Ajax

In this post I show a sample of a WCF 3.5 service which supports Json.

WebGetAttribute.ResponseFormat Property

The WebMessageFormat property determines the format of responses sent from a service operation. The two possibe values are Xml and Json.

The following example demonstrates how to set the ResponseFormatProperty:

[ServiceContract]

public interface IService

{

    [OperationContract]

    [WebGet(ResponseFormat = WebMessageFormat.Json)]

    String SayHello(String name);

}

The implementation of this service is simple:

public class Service : IService

{

    public String SayHello(String name)

    {

        return String.Format("Hello {0}", name);

    }

}

 

Web.Config

In Web.Config the service include webHttpBinding and jasonBehavior which contain the enableWebScript element.

 

The enableWebScript element enables the endpoint behavior that makes it possible to consume the service from ASP.NET AJAX web pages. This behavior should be used in conjunction with either <webHttpBinding> or <webMessgaeEncoding> binding element.

 

    <system.serviceModel>

        <services>

            <service behaviorConfiguration="ServiceBehavior" name="Service">

                <endpoint

                    address=""

                    binding="webHttpBinding"

                    behaviorConfiguration="jsonBehavior"

                    contract="IService"/>

                <endpoint

                    address="mex"

                    binding="mexHttpBinding"

                    contract="IMetadataExchange"/>

            </service>

        </services>

        <behaviors>

            <serviceBehaviors>

                <behavior name="ServiceBehavior">

                    <serviceMetadata httpGetEnabled="true"/>

                    <serviceDebug includeExceptionDetailInFaults="false"/>

                </behavior>

            </serviceBehaviors>

            <endpointBehaviors>

                <behavior name="jsonBehavior" >

                    <enableWebScript/>

                </behavior>

            </endpointBehaviors>

        </behaviors>

    </system.serviceModel> 

 

ClientPage.htm

The client page create an Ajax XMLHttpRequest object, construct the url to the service and prints the response.

 

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head></head>

<body>

<h1>AJAX WCF Sample</h1>

<form name="input">

    Name: <input type="text" name="name" onclick="sayHello();" />

    <div id="msg"></div>

</form>

 

<script type="text/javascript">

function sayHello()

{

    var xmlHttp;

    try

    {

        xmlHttp = new XMLHttpRequest();

    }

    catch (e)

    {

        try

        {

            xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");

        }

        catch (e)

        {

            try

            {

                xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");

            }

            catch (e)

            {

                var msg = "This sample only works";

                msg = msg + "in browsers with AJAX support.";

                alert(msg);

 

                return false;

            }

        }

    }

 

    xmlHttp.onreadystatechange = function()

    {

        if (xmlHttp.readyState == 4)

        {

            var mdiv = document.getElementById("msg");

            mdiv.innerHTML = (xmlHttp.responseText);

        }

    }

 

    var url = "Service.svc/";

    url = url + "SayHello?name=";

    url = url + document.input.name.value;

 

    xmlHttp.open("GET", url, true);

    xmlHttp.send('');

}

</script>

</body>

</html> 

 

The result

 

WCF Ajax

The source for this sample can be downloaded from here.

 

 

 

 

Posted: Jan 31 2008, 03:31 PM by egady | with 9 comment(s)
תגים:, ,

Visual Studio 2008 SDK - Create Project using SDK

Visual Studio 2008 SDK - Create Project using SDK

The following sample illustrates how to add new project into Visual Studio 2008 using the SDK, and add C# file into this project.

1) Create in Visual Studio 2008 new VsPackage project ('MyVSPackage') as shown in the following picture:

Microsoft Visual Studio 2008 SDK - Create VsPackage

2) Choose C# as the language, and also select the Menu Item Command check box.

3) Add a reference to EnvDTE assembly.

EnvDTE is an assembly-based COM library, used for Visual Studio Automation. You can access projects, automate creation of solution and projects etc.

4) Put the following code in method: MyVSPackagePackage.MenuItemCallback()

    private void MenuItemCallback(object sender, EventArgs e)

    {

        IVsSolution solution = (IVsSolution)GetService(typeof(SVsSolution));

        if (solution != null)

        {

            IntPtr ppProject;

            Guid rguidProjectType = Guid.Empty;

            Guid iidProject = Guid.NewGuid();

 

            uint grfCreateFlags = (uint)(

               __VSCREATEPROJFLAGS.CPF_CLONEFILE |

               __VSCREATEPROJFLAGS.CPF_OVERWRITE);

 

            // Creates the project 'MyProject.csproj'.

            Int32 result = solution.CreateProject(

                ref rguidProjectType,

                @"C:\Library.csproj",

                @"C:\MyProj",

                "MyProj",

                grfCreateFlags,

                ref iidProject,

                out ppProject);

 

            if (result != VSConstants.S_OK)

            {

                return;

            }

 

            IVsHierarchy ppHierarchy = null;

            result = solution.GetProjectOfGuid(ref rguidProjectType, out ppHierarchy);

 

            if (ppHierarchy != null && result == VSConstants.S_OK)

            {

                Object automationObject = null;

                ppHierarchy.GetProperty(

                    VSConstants.VSITEMID_ROOT,

                    (Int32)__VSHPROPID.VSHPROPID_ExtObject,

                    out automationObject);

 

                if (automationObject != null)

                {

                    EnvDTE.SolutionClass sc = automationObject as EnvDTE.SolutionClass;

                    EnvDTE.Projects projects = sc.Projects;

                    EnvDTE.Project project = projects.Item(1);

                    EnvDTE.ProjectItems pitems = project.ProjectItems;

 

                    pitems.AddFromFileCopy(@"c:\MyCS.cs");

                }

            }

        }

    }

 

  • Interface IVsSolution - Provides a top level maintanance for the solution. This interface is part of the Microsoft.VisualStudio.Shell.Interop Namespace.
  • Method IVsSolution.CreateProject() - Creates the new project (can also open a project).

5) Run the solution, and an Experimental Visual Studio will open.

Select Tools-->My Command Name to trigger the MenuItemCallback(), a new project 'MyProj' is added including a C# file (MyCS.cs).

  • The Project name and directory is: MyProj
  • The file Library.csproj is a template for cs project.

 The source code for this project can be downloaded here.

HTTP Web Programming with WCF 3.5: Creating a Template based URI

The .NET Framework 3.5 include support for web development using WCF.
In this post I will show how to create template based URI and to use them.

UriTemplate and UriTemplateMatch types

A UriTemplate is composed of two parts: a path and a query. The following examples show valid templates:

finance/nasdaq/quote
finance/{market}/{quote}
finance/*
finance/{market}/{quote}?s=MSFT
finance/{market}/{quote}?s={ticket}

Elemets of the query must consists of pairs: s=MSFT or s={ticket}.

The following sample show how to create a UriTemplate, bind and match it to a candidate URI.

    UriTemplate template = new UriTemplate("finance/{market}/quote?s={ticket}");

    Uri prefix = new Uri("http://localhost:8080");

 

    foreach (String name in template.PathSegmentVariableNames)

    {

        Console.WriteLine("{0} ", name); // MARKET

    }

 

    foreach (String name in template.QueryValueVariableNames)

    {

        Console.WriteLine("{0} ", name); // TICKET

    }

 

Two ways for binding the uri template:

 

    // 1) http://localhost:8080/finance/nasdaq/quote?s=MSFT

    Uri positionalUri = template.BindByPosition(prefix, "nasdaq", "MSFT");

    Console.WriteLine("{0}", positionalUri);

 

    // 2) http://localhost:8080/finance/nasdaq/quote?s=MSFT

    NameValueCollection parameters = new NameValueCollection();

    parameters.Add("market", "nasdaq");

    parameters.Add("ticket", "MSFT");

    Uri namedUri = template.BindByName(prefix, parameters);

    Console.WriteLine("{0}", namedUri);

 

 

URI Template Match:

 

    Uri fullUri = new Uri("http://localhost/finance/nasdaq/quote?s=MSFT");

    UriTemplateMatch results = template.Match(prefix, fullUri);

 

    // MARKET: nasdaq

    // TICKET: MSFT

    if (results != null)

    {

        foreach (String variableName in results.BoundVariables.Keys)

        {

            Console.WriteLine("{0}: {1}\n", variableName, results.BoundVariables[variableName]);

        }

    }

 

    // nasdaq

    String market = results.BoundVariables["market"];

 

    // MSTF

    String ticket = results.BoundVariables["ticket"];

 

WebGet and WebInvoke 

 

The following code describe a service contract for the WCF service itself:

 

    [ServiceContract]

    public interface IStockService

    {

        [OperationContract]

        [WebGet(UriTemplate = "finance/{market}/quote?s={ticket}")]

        String GetQuote(String market, String ticket);

 

        [OperationContract]

        [WebInvoke(UriTemplate = "Hello", Method="POST")]

        String GetPrice();

    }

 

For each parameter in the UriTemplate, there is a corresponding parameter in the GetQuote method.

 

The implementation of the web service is simple:

 

    public class StockService : IStockService

    {

        public String GetQuote(String market, String ticket)

        {

            return "33.91";

        }

 

        public String GetPrice()

        {

            return "33";

        }

    }

 

WCF Hosting using the WebHttpBehavior and WebHttpBinding:

 

    using (ServiceHost host = new ServiceHost(typeof(StockService),

        new Uri("http://localhost:8080/")))

    {

        WebHttpBinding binding = new WebHttpBinding();

 

        ServiceEndpoint ep = host.AddServiceEndpoint(

            typeof(IStockService), binding, String.Empty);

 

        ep.Behaviors.Add(new WebHttpBehavior());

 

        host.Open();

 

        Console.ReadKey();

    }

 

The Client

And finally, the client can be any http client as show in the following sample code:

 

    using (WebClient client = new WebClient())

    {

        String address = "http://localhost:8080/finance/nasdaq/quote?s=MSFT";

        String price = client.DownloadString(address);

 

        // Results:

        // <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">33.91</string>

 

        String address2 = "http://localhost:8080/Hello";

        client.Headers.Add(HttpRequestHeader.ContentType, "text/xml");

        String price2 = client.UploadString(address2, "POST", "MSFT");

        // Result:

        // <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">33</string>

    }

 

You can download here the source code.

 

Posted: Jan 14 2008, 04:42 PM by egady | with 4 comment(s)
תגים:, ,

Creating Durable Service in WCF 3.5

Creating Durable Services in WCF 3.5

The .NET Framawork 3.5 includes support for WCF durable services, which use the WF persistence model to persist the state of a service. Those services are designed to be durable and long running, and to survive application and server restarts. In this post I will show a way to store the context at the client side.

Long Running and Application/Server restarts

When the client initiates the conversation with the service, the framework persist the state after the operation completed. When the client continues the conversation with the service at a later time, the framework gets the token from the message, restore the state according to that token, and gets the service with the state that used the last time speaking with that client.

The following code sample demonstrates creating a durable service which supports wsHttpContextBinding and basicHttpContextBinding, lets start with the service contract and implementation:

    [ServiceContract(Namespace = "http://DurableService")]

    public interface IDurableService

    {

        [OperationContract()]

        String Start(String str);

 

        [OperationContract()]

        String Call(String str);

 

        [OperationContract()]

        void Done();

    } 

 

    [Serializable]

    [DurableService]

    public class DurableService : IDurableService

    {

        String m_state;

 

        [DurableOperation(CanCreateInstance = true)]

        public String Start(String str)

        {

            m_state = str;

            return m_state;

        }

 

        [DurableOperation(CanCreateInstance = false)]

        public String Call(String str)

        {

            m_state += str;

            return m_state;

        }

 

        [DurableOperation(CompletesInstance = true)]

        public void Done()

        {

        }

    }

 

Notice: when you generate the client as a web reference, the VS 2008 put basicHttpBinding instead of basicHttpContextBinding and the client app.config!

Automatic Persistence via Pluggable Provider

The way to store the state is plug-gable, by hooking the persistence provider, you can provide the storage, which is done by SqlPersistenceProviderFactory, or by providing custom persistence provider which derived from PersistenceProvider or LockingPersistenceProvider.

For simplifying the sample, I used a custom provider FilePersistenceProviderFactory, taken from Microsoft samples.

        <services>

            <service name="DurableService.DurableService" behaviorConfiguration="ServiceBehavior">

                <host>

                    <baseAddresses>

                        <add baseAddress="http://localhost:8080/DurableService"/>

                    </baseAddresses>

                </host>

                <endpoint address="ContextOverHttp"

                          binding="wsHttpContextBinding"

                          contract="DurableService.IDurableService" />

                <endpoint address=""

                          binding="basicHttpContextBinding"

                          contract="DurableService.IDurableService" />

            </service>

        </services>

        <behaviors>

            <serviceBehaviors>

                <behavior name="ServiceBehavior">

                    <serviceMetadata httpGetEnabled="true" />

                    <persistenceProvider 

                        type="Microsoft.WorkflowServices.Samples.FilePersistenceProviderFactory,

                              Service, Version=1.0.0.0" />

                </behavior>

            </serviceBehaviors>

        </behaviors>


Automatic Propagation of Context Token 

The client in this program, store the context in a durable place (token_context.bin) in the first time a conversation is initiated. When the client restarted, he check weather a context is existed, and if so - call the next workflow operation, otherwise - initiates new workflow.

The token context is propagated automatically by the framework, and passed by HTTP cookie or by SOAP header. 

The following code show a simple Helper class, which provided for managing the context in the client side:

    public class Helper

    {

        static readonly String TokenContextFileName = "token_context.bin";

 

        public static IDictionary<String, String> LoadContext()

        {

            IDictionary<String, String> ctx = null;

 

            try

            {

                using (FileStream fs =

                    new FileStream(TokenContextFileName, FileMode.Open, FileAccess.Read))

                {

                    BinaryFormatter bf = new BinaryFormatter();

                    ctx = bf.Deserialize(fs) as IDictionary<String, String>;

                    fs.Close();

                }

            }

            catch (Exception ex)

            {

            }

            return ctx;

        }

 

        public static void SaveContext(IClientChannel channel)

        {

            IContextManager cm = channel.GetProperty<IContextManager>();

            IDictionary<String, String> ctx = cm.GetContext() as IDictionary<String, String>;

 

            try

            {

                using (FileStream fs = new FileStream(TokenContextFileName, FileMode.Create))

                {

                    BinaryFormatter bf = new BinaryFormatter();

                    bf.Serialize(fs, ctx);

                    fs.Close();

                }

            }

            catch (Exception ex)

            {

            }

        }

 

        public static void DeleteContext()

        {

            try

            {

                File.Delete(TokenContextFileName);

            }

            catch (Exception ex)

            {

            }

        }

 

        public static void SetContext(IClientChannel channel, IDictionary<String, String> ctx)

        {

            IContextManager cm = channel.GetProperty<IContextManager>();

            cm.SetContext(ctx);

        }

    }

 

The Client

 

And finally, the client code, which I make here a scenario of "client restars":

 

    class Program

    {

        private static IDictionary<String, String> TokenContext = Helper.LoadContext();

 

        static void Main(String[] args)

        {

            if (TokenContext == null)

            {

                String str = Start("Hello");

                return// client restarts

            }

            else

            {

                String str1 = Call(" There");

                String str2 = Call("!");

                Done();

            }

        }

 

        public static String Start(String str)

        {

            DurableServiceClient proxy = new DurableServiceClient();

            String s = proxy.Start(str);

            Helper.SaveContext(proxy.InnerChannel);

            proxy.Close();

            return s;

        }

 

        public static String Call(String str)

        {

            DurableServiceClient proxy = new DurableServiceClient();

            Helper.SetContext(proxy.InnerChannel, TokenContext);

            String s = proxy.Call(str);

            proxy.Close();

            return s;

        }

 

        public static void Done()

        {

            DurableServiceClient proxy = new DurableServiceClient();

            Helper.DeleteContext();

            proxy.Done();

            proxy.Close();

        }

    }

 

The source code of this sample: http://blogs.microsoft.co.il/blogs/egady/WCF/DurableService.zip

Gady's First Blog Entry

My name is Gady Elkarif, and as I used the blog community so often, I decided to join to this unstoppable force, and start blogging myself.

I am working in a software company (SAP) in the IW Group (Duet), and in the last year I worked with WCF, although I actually do a fair amount of things in .NET.

The intent of this blog is to share ideas on WCF, VS SDK, design, performance and much more...

Hope you will find this blog interesting - wish me luck (and return back...)