DCSIMG
Gady Elkarif's Blog

Gady Elkarif's Blog

Writing Custom Web Services for SharePoint

Writing Custom Web Services for SharePoint

As a SharePoint developer, you may want to use some of the capabilities of Windows SharePoint Services to create custom Web services of your own.

In this sample I will show you how to use the SharePoint to create a custom Web service inside SharePoint.

Writing a Custom Web Service

Create new ASP.NET Web Service Application (MySPServices) as shown in the following figure:

NewProject

Next, add new Service Library (MySPServicesLibrary) project to the ASP.NET Application:

AddNewProject

Add to MySPServicesLibrary project a reference to System.Web.Services.

Rename Class1.cs in MySPServicesLibrary project to MySPService.cs, and insert your web service code. In this sample the following code describes MySPService.cs:

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Linq;

    4 using System.Text;

    5 using System.ComponentModel;

    6 using System.Web.Services;

    7 

    8 namespace MySPServicesLibrary

    9 {

   10     /// <summary>

   11     /// Summary description for Service1

   12     /// </summary>

   13     [WebService(Namespace = "http://tempuri.org/")]

   14     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

   15     [ToolboxItem(false)]

   16     public class MySPService : System.Web.Services.WebService

   17     {

   18 

   19         [WebMethod]

   20         public void AddEntity(Entity customer)

   21         {

   22 

   23         }

   24     }

   25 

   26     public class Entity

   27     {

   28         public string Name { get; set; }

   29     }

   30 }

In MySPServicesLibrary, righclick on the project name and select properties, then select Signing tab, for signing the assembly:

Signing

Build MySPServicesLibrary project.

Open Visual Studion Command Prompt, and type the following command:

sn -Vr MySPServicesLibrary.dll

This will result a Public Key Token. View the markup of the MySPService.asmx (Right Click –> View Markup) and replace the following line:

<%@ WebService Language="C#" CodeBehind="Service1.asmx.cs" Class="MySPServices.Service1" %>

With this line, and update the PublicKeyToken you get from using the sn tool.

<%@ WebService Language="C#" Class="MySPServicesLibrary.MySPService, MySPServicesLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=55D195EC7508F2D2" %>

In MySPServices application, removes Service1.asmx.cs, and rename Service1.asmx to MySPService.asmx.

Add reference from MySPServices application to MySPServicesLibrary.dll and test that your web service is working.

Generating and Modifying Static Discovery and WSDL Files

Copy MySPServicesLibrary.dll into the GAC (C:\WINDOWS\assembly).

Open the Visual Studio .NET command prompt, and go to the LAYOUT directory:

C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS

Copy MySPService.asmx into this directory.

Run the following command:

disco.exe /MySPService.asmx">/MySPService.asmx">http://<your service url>/MySPService.asmx

The output is two files:

  • MySPService.disco
  • MySPService.wsdl
Open CustomerService.disco and CustomerService.wsdl, and replace the first line in both files:
<?xml version="1.0" encoding="utf-8"?>
with the following content:

<%@ Page="" Language="C#" Inherits="System.Web.UI.Page"    %>

  <%@ Assembly="" Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    <%@ Import="" Namespace="Microsoft.SharePoint.Utilities" %>

      <%@ Import="" Namespace="Microsoft.SharePoint" %>

        <% Response.ContentType = "text/xml"; %>

 

Rename the files MySPService.disco to MySPServicedisco.aspx and MySPService.wsdl to MySPServicewsdl.aspx .

Updating MySPServicedisco.aspx

In the .disco file, replace the contactRef and soap tags with the following content:

 

        <discovery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/disco/">

          <contractRef ref=""

          <% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request) + "?wsdl"),Response.Output); %> docRef=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> xmlns="http://schemas.xmlsoap.org/disco/scl/" />

          <soap address=""

          <% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>

xmlns:q1="http://schemas.microsoft.com/sharepoint/soap/" binding="q1:MySPServiceSoap" xmlns="http://schemas.xmlsoap.org/disco/soap/" />

          <soap address=""

          <% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> xmlns:q2="http://schemas.microsoft.com/sharepoint/soap/" binding="q2:MySPServiceSoap12" xmlns="http://schemas.xmlsoap.org/disco/soap/" />

        </discovery>

Updateing MySPServicewsdl.aspx

In the .wsdl file, replace soap:address and soap12:address tags with the following content:

  <wsdl:service name="MySPService">

    <wsdl:port name="MySPServiceSoap" binding="tns:MySPServiceSoap">

      <soap:address location=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> />

    </wsdl:port>

    <wsdl:port name="MySPServiceSoap12" binding="tns:MySPServiceSoap12">

      <soap12:address location=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> />

    </wsdl:port>

Copy the files MySPServicedisco.aspx MySPServicewsdl.aspx and MySPService.aspx into directory: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI

Goto the following URL to verify the web service successfully created:

http://MyServer/_vti_bin/MySPService.asmx

http://MyServer/_vti_bin/MySPService.asmx?wsdl

http://MyServer/_vti_bin/MySPService.asmx?disco

Consuming the SharePoint Web Service

Create new console application project and add a web reference to the new custom web service. The following code show how I can use the web service I created:

    1         static void Main(string[] args)

    2         {

    3             try

    4             {

    5                 MySPServiceSoapClient svc = new MySPServiceSoapClient();

    6 

    7                 Entity entity = new Entity()

    8                 {

    9                     Name = "SampleEntity"

   10                 };

   11 

   12                 svc.AddEntity(entity);              

   13 

   14                 svc.Close();

   15             }

   16             catch (Exception ex)

   17             {

   18             }

   19         }

If you get the following security exception:

The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'.

Go to the client app.config and change the security settings of the WCF binding as follows:

                    <security mode="TransportCredentialOnly">

                        <transport clientCredentialType="Windows" proxyCredentialType="Windows"

                            realm="" />

                        <message clientCredentialType="UserName" algorithmSuite="Default" />

                    </security>

Working with Master Pages

Working with Master Pages

For many sites, there is a need for reusable way for maintaining a standardized appearance across the entire site. Those sites include common headers, footers and menus.

Master Pages in ASP.NET 2.0 consists of two conceptual elements:

  • Master Pages
  • Content Pages

At runtime, the ASP.NET engine combines these elements into a single page for the end user.

Master Pages is a feature coming in ASP.NET 2.0, which enables to create sites with a common appearance driven by a single template. You can create a single template page that can be used as a foundation for any number of ASP.NET content pages in your application.

Master Pages

Master page file serves as the template for other pages, and contains the top-level HTML elements like header, navigation, footer, Ad space and common items.

The main differences between standard ASP.NET page to master page:

  • <%@ master %> directive
  • .master extension

You can add master pages in the same way you add .aspx pages – choose Master Page option when you add new item to your application, as shown in the following figure:

CreateMasterPage

The default master page that created for you contains the following content:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site1.master.cs" Inherits="MasterPages.Site1" %>

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

<head runat="server">

    <title>Untitled Page</title>

    <asp:ContentPlaceHolder ID="head" runat="server">

    </asp:ContentPlaceHolder>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">

        </asp:ContentPlaceHolder>

    </div>

    </form>

</body>

</html>

Content Pages

Content Pages are ordinary aspx pages, that contains a reference to a master page. Their purpose is to provides the content for the inherited master page template.

The following code is the content of Default.aspx, which cause the result in the below image. In each asp:content tag you specify for which ContentPlaceHolderID in the master page to insert the content.

<%@ Page="" Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="MasterPages._Default" MasterPageFile="~/Site1.Master" %>

<asp:content ID="Content1" ContentPlaceHolderID="head" runat="server">

    Default page

</asp:content>

<asp:content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">

    This is the content for the default page.

</asp:content>

DefaultPage

One of the implications of this implementation is that master page is just another control in your page, which means it accessible in code:

<script runat="server">

        void Page_Load(object sender, EventArgs e)

        {

            HtmlForm form = Master.FindControl("form1") as HtmlForm;

            if (form != null)

            {

            }

        }

</script>

 

Using Visual Studio 2008 Designer

The great thing in master pages in Visual Studio 2008 is that you can use the designer and switch to code as any .aspx page. For example for the following master page:

<%@ Master="" Language="C#" AutoEventWireup="true" CodeBehind="Site2.master.cs" Inherits="MasterPages.Site2" %>

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

        <head runat="server">

            <title>Untitled Page</title>

            <asp:ContentPlaceHolder ID="head" runat="server">

            </asp:ContentPlaceHolder>

        </head>

        <body>

            <form id="form1" runat="server">

                <table cellpadding="3" border="1">

                    <tr bgcolor="yellow">

                        <td colspan="2">

                            <h1>My Home Page</h1>

                        </td>

                    </tr>

                    <tr>

                        <td>

                            <asp:ContentPlaceHolder ID="ContentPlaceHolder3" runat="server">

                            </asp:ContentPlaceHolder>

                        </td>

                        <td>

                            <asp:ContentPlaceHolder ID="ContentPlaceHolder4" runat="server">

                            </asp:ContentPlaceHolder>

                        </td>

                    </tr>

                    <tr>

                        <td colspan="2">

                            Copyright 2009

                        </td>

                    </tr>

                </table>

                <div>

                    <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">

                    </asp:ContentPlaceHolder>

                </div>

            </form>

        </body>

    </html>

Lets change the Default.aspx page as follow:

<%@ Page="" Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="MasterPages._Default" MasterPageFile="~/Site2.Master" %>

    <asp:content ID="Content1" ContentPlaceHolderID="head" runat="server">

        Default page

    </asp:content>

    <asp:content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">

        This is the content for the default page.

    </asp:content>

    <asp:content ID="Content4" ContentPlaceHolderID="ContentPlaceHolder3" runat="server">

        ContentPlaceHolder3

    </asp:content>

    <asp:content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder4" runat="server">

        ContentPlaceHolder4

    </asp:content>

You can edit the master page using the Visual Studio 2008 Designer as shown in the following figure:

MasterPage

Conclusion

Master pages is a great enhancement to your web pages, and by using a single template page it can be used as a foundation for any number of ASP.NET pages in your site. This template make it easier to develop and manage sites, and supported by the Visual Studio 2008 Designer.

SharePoint Site Variations

SharePoint Site Variations

The variations feature in Office SharePoint Server 2007 helps creating multilingual site hierarchy, which makes content available by copying content from the source variation site to each target variation site in the hierarchy.

After installing the Hebrew Language Pack, I want to create site variation hierarchy with two sites:

  • English site (Source)
  • Hebrew site (Target)

Use the following steps to create SharePoint site variations:

  • Create New Web Application
  • Create Site Variation
  • Create Variation Labels

Create New Web Application

In the SharePoint Central Administration page, select Application Management, and then select “Create or extend Web application” link.

SharePoint: Create or Extend Web Application SharePoint: Create New Web Application

In the Create or Extend Web Application page, enter the user name and password, and click OK.

SharePoint: Create New Web Application

In the Application Created page press on Create Site Collection link.

SharePoint: Application Created

In the Create Site Collection, select title, URL and site template. Provide also user name and press OK.

SharePoint: Create Site Collection 

Verify your site collection was successfully created in the following URL:

http://myhost:port/sites/MySiteCollection

SharePoint: Site Collection

Create Site Variation

Press on “Set up multilingual support” link to create variation home. Type slash (‘/’) to indicate the top-level Web site of the site collection and press OK.

To go to variation in the menu, go to Modify All site settings, and then select variations.

SharePoint: Modify All Site Settings

Create Variation Labels

A variation label is an identifier that is used to name and configure a new variation site in the variation hierarchy. You can select only one variation label as the source, which represents the main site where content enters the system. The corresponding variation labels are the target labels, representing the sites to which content is copied.

Select variation label, set label name, display name, site template language and locale for both the English site and the Hebrew site.

In addition, for the English site, creates it as the source hierarchy.

SharePoint: Create Variation Label SharePoint: Create Hebrew Variation Label

Press on “Create Hierarchies” operation and go to the site collection home page, this is the result I get:

SharePoint: Site Variation

Check the Result

If you put in the browser the following URL: http://myhost:port/sites/MySiteCollection

You will redirected to the appropriate variation (English / Hebrew) according to the definition of the default language preferences in your browser:

Language Preferences 

If you add and publish a new page in the English site, it will duplicated to the other sites in the hierarchy.

Technorati Tags:

Book Review: RESTful PHP Web Services

Book Review: RESTful PHP Web Services

RESTful PHP Web Services by Samisa Abeysinghe.

The book is full of great information about REST with PHP, and assumes you have a working knowledge of PHP. It starts with introducing the principles behind REST, what is REST web services, why use it, and some REST tools and frameworks in PHP.

You will study on some real-world REST applications, designing and implementing a resource-oriented client and service in detail and much more.

The book is short (200 pages), and has some identications problems in code samples, but I have no problem with that.

The book contains a lots of examples in PHP, and I think more explanations on the sameples could help in some places. 

Conclusion

I would recommend this book for beginners PHP developer as it is a good introduction to PHP web services using REST style. Also for experienced PHP programmers who interesting in REST.

Enjoy!

 


 

Asynchronous ASP.NET 2.0 Programming

Asynchronous ASP.NET 2.0 Programming

One of the coolest features in ASP.NET 2.0 is asynchronous pages. This feature increase scalability by using thread-pool threads more efficiently.

With asynchronous pages, a thread which assigned from the thread-pool to process page request, is returned to the thread pool instead of waiting for an I/O operation to complete. This means more threads available to process incoming requests, and when I/O operation is completed, another thread from the pool is guarantee to send back the response.

There are 3 asynchronous programming model in ASP.NET 2.0:

  • Asynchronous Pages
  • Asynchronous HTTP Handlers
  • Asynchronous HTTP Modules

In this post I will cover the asynchronous pages programming model.

Asynchronous Pages in ASP.NET 2.0

Let's start by including an Async="true" attribute in the @Page directive. This tells ASP.NET to implement IHttpAsyncHandler in the page.

<%@ Page="" Async="true" Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

AddOnPreRenderCompleteAsync

In Page_Load (or any early Page's life time) we can call to the AddOnPreRenderCompleteAsync method, to register begin and end methods, as shown in the following code:

using System;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.Net;

using System.IO;

 

public partial class _Default : System.Web.UI.Page

{

    private WebRequest _request;

 

    protected void Page_Load(object sender, EventArgs e)

    {

        AddOnPreRenderCompleteAsync(

            new BeginEventHandler(BeginAsyncOperation),

            new EndEventHandler(EndAsyncOperation)

        );

    }

 

    IAsyncResult BeginAsyncOperation(object sender, EventArgs e,

        AsyncCallback asyncCallback, object state)

    {

        _request = WebRequest.Create("http://blogs.microsoft.co.il/blogs/egady");

 

        return _request.BeginGetResponse(asyncCallback, state);

    }

 

    void EndAsyncOperation(IAsyncResult asyncResult)

    {

        using (WebResponse response = _request.EndGetResponse(asyncResult))

        {

            using (StreamReader reader =

                new StreamReader(response.GetResponseStream()))

            {

                string str = reader.ReadToEnd();

 

                Response.Write(str);

            }

        }

    }

}

The BeginAsyncOperation can launch an asynchronous operation such database call, or web service call, and return immediately. When this operation is completed, another thread continue from the EndAsyncOperation method to complete the request and send the response back to the client!

The result of the code is showing in the following image:

Asynchronous ASP.NET 2.0 Programming 

RegisterAsyncTask

What if you want to perform several asynchronous I/O operations in an asynchronous page which not involved remote web service/database calls? We can call AddOnPreRenderCompleteAsync multiple times, and it will cause the tasks to execute sequentially - next begin method not called until previous end method returns. For concurrent execution it will requires you to compose IAsyncResult.

The RegisterAsyncTask can helps us with this, by calling it multiple times (one per task). The tasks can be executed sequentially or concurrently, and prevent us from implementing IAsyncResult!

The following code cause to the same result like the above sample with AddOnPreRenderCompleteAsync:

using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.Net;

using System.IO;

 

public partial class Default2 : System.Web.UI.Page

{

    private WebRequest _request;

 

    protected void Page_Load(object sender, EventArgs e)

    {

        PageAsyncTask task = new PageAsyncTask(

            new BeginEventHandler(BeginAsyncOperation),

            new EndEventHandler(EndAsyncOperation),

            new EndEventHandler(TimeoutAsyncOperation), null

        );

        RegisterAsyncTask(task);

    }

 

    IAsyncResult BeginAsyncOperation(object sender, EventArgs e,

        AsyncCallback asyncCallback, object state)

    {

        _request = WebRequest.Create("http://blogs.microsoft.co.il/blogs/egady");

 

        return _request.BeginGetResponse(asyncCallback, state);

    }

 

    void EndAsyncOperation(IAsyncResult asyncResult)

    {

        using (WebResponse response = _request.EndGetResponse(asyncResult))

        {

            using (StreamReader reader =

                new StreamReader(response.GetResponseStream()))

            {

                string str = reader.ReadToEnd();

 

                Response.Write(str);

            }

        }

    }

 

    void TimeoutAsyncOperation(IAsyncResult asyncResult)

    {

    }

}

You can decide if the task will run in parallel or sequentially by the fifth parameter of the PageAsyncTask constructor:

  • true - Execute in parallel
  • false - Execute in series

ExecuteRegisteredAsyncTasks - Execute registered async tasks immediately, and synchronously - Please don't use this method!!

Context Flow

Another advantage of RegisterAsyncTask is that it flows request context from begin threads to end threads, and that includes:

  • HttpContext
  • Impersonation
  • Culture

While in AddOnPreRenderCompleteAsync HttpContext.Current will be null in end threads, and end threads also revert to process identity.

Conclusion

Asynchronous programming can make your application more scalable, by using the ASP.NET thread-pool more efficiently. When you take the 5-10 pages in your site, that are used mostly and have the heaviest remote I/O operations, and convert them into asynchronous pages, you can more than double your traffic into your site!

References:

kick it on DotNetKicks.com
Posted: Sep 29 2008, 04:47 AM by egady | with 7 comment(s) |
תגים:,

Acyclic Visitor Design Pattern

Acyclic Visitor Design Pattern

The Visitor Design Pattern allow new functions to be added to existing class hierarchies without affecting those hierarchies. The Acyclic Visitor Design Pattern is saved you from implementing some unrequired methods using downcasting.

The following code sample display 3 elements: Element1, Element2 and Element3, and two concrete visitors: Visitor12 and Visitor3.

The Acyclic Visitor Design Pattern is preventing you from implement method Visit(Element3) in Visitor12, and methods Visit(Elemen1), Visit(element2) in Visitor3.

The Source Code

    public interface IVisitor

    {

    }

 

    public interface IElement1Visitor

    {

        void Visit(Element1 element);

    }

 

    public interface IElement2Visitor

    {

        void Visit(Element2 element);

    }

 

    public interface IElement3Visitor

    {

        void Visit(Element3 element);

    }

 

    public class Visitor12 : IVisitor, IElement1Visitor, IElement2Visitor

    {

        public void Visit(Element1 element)

        {

 

        }

 

        public void Visit(Element2 element)

        {

 

        }

    }

 

    public class Visitor3 : IVisitor, IElement3Visitor

    {

        public void Visit(Element3 element)

        {

 

        }

    }

 

    public abstract class AbstractElement

    {

        public abstract void Accept(IVisitor visitor);

    }

 

    public class Element1 : AbstractElement

    {

        public override void Accept(IVisitor visitor)

        {

            IElement1Visitor element1Visitor = visitor as IElement1Visitor;

            if (element1Visitor == null)

            {

                return;

            }

 

            element1Visitor.Visit(this);

        }

    }

 

    public class Element2 : AbstractElement

    {

        public override void Accept(IVisitor visitor)

        {

            IElement2Visitor element2Visitor = visitor as IElement2Visitor;

            if (element2Visitor == null)

            {

                return;

            }

 

            element2Visitor.Visit(this);

        }

    }

 

    public class Element3 : AbstractElement

    {

        public override void Accept(IVisitor visitor)

        {

            IElement3Visitor element3Visitor = visitor as IElement3Visitor;

            if (element3Visitor == null)

            {

                return;

            }

 

            element3Visitor.Visit(this);

        }

    }

 


Posted: Aug 19 2008, 03:29 AM by egady | with 1 comment(s)
תגים:,

Serializable CollectionBase Class

Serializable CollectionBase Class

The idea of class CollectionBase is to have a base class which is based on list for serialization, and also on dictionary for fast retrieval.

So I have tried to create class CollectionBase class which is serializable, and when I try to serialize it with XmlSerializable, I got the following runtime exception:

"To be XML serializable, types which inherit from IEnumerable must have an implementation of Add(System.Object) at all levels of their inheritance
hierarchy."

The following sample code show the correct implementation of CollectionBase:

CollectionBase Usage

public class MyDerivedClass : CollectionBase<MyItem>

{

 

}

 

public class MyItem: IIdentifier

{

    public string Key

    {

        get;

        set;

    }

}

 

 

CollectionBase Implementation

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace MyCollections

{

    public interface IIdentifier

    {

        string Key

        {

            get;

            set;

        }

    }

 

    public class CollectionBase<TItem> : IList<TItem> where TItem : class, IIdentifier

    {

        private IDictionary<string, TItem> _itemsMap = new Dictionary<string, TItem>();

 

        private List<TItem> _items = new List<TItem>();

 

        public virtual void Add(Object item)

        {

            TItem ii = item as TItem;

 

            if (ii == null)

            {

                return;

            }

            this[ii.Key] = ii;

        }

 

 

        public TItem this[string key]

        {

            get

            {

                return _itemsMap[key];

            }

            set

            {

                try

                {

                    if (value == null)

                    {

                        return;

                    }

                    _items.Add(value);

 

                    _itemsMap[value.Key] = value;

                }

                catch (ArgumentOutOfRangeException)

                {

 

                }

            }

        }

 

        #region IList<TItem> Members

 

        int IList<TItem>.IndexOf(TItem item)

        {

            return _items.IndexOf(item);

        }

 

        void IList<TItem>.Insert(int index, TItem item)

        {

            try

            {

                if (item == null)

                {

                    return;

                }

                _items.Insert(index, item);

 

                _itemsMap[item.Key] = item;

            }

            catch (ArgumentOutOfRangeException)

            {

 

            }

        }

 

        void IList<TItem>.RemoveAt(int index)

        {

            try

            {

                TItem item = _items[index];

 

                _items.RemoveAt(index);

 

                _itemsMap.Remove(item.Key);

            }

            catch (ArgumentOutOfRangeException)

            {

 

            }

        }

 

        TItem IList<TItem>.this[int index]

        {

            get

            {

                return _items[index];

            }

            set

            {

                try

                {

                    if (value == null)

                    {

                        return;

                    }

                    _items[index] = value;

 

                    _itemsMap[value.Key] = value;

                }

                catch (ArgumentOutOfRangeException)

                {

 

                }

            }

        }

 

        #endregion

 

        #region ICollection<TItem> Members

 

        void ICollection<TItem>.Add(TItem item)

        {

            if (item == null)

            {

                return;

            }

            _items.Add(item);

 

            _itemsMap[item.Key] = item;

        }

 

        void ICollection<TItem>.Clear()

        {

            _items.Clear();

 

            _itemsMap.Clear();

        }

 

        bool ICollection<TItem>.Contains(TItem item)

        {

            if (item == null)

            {

                return false;

            }

            return _itemsMap.ContainsKey(item.Key);

        }

 

        void ICollection<TItem>.CopyTo(TItem[] array, int arrayIndex)

        {

            throw new NotImplementedException();

        }

 

        int ICollection<TItem>.Count

        {

            get { return _items.Count(); }

        }

 

        bool ICollection<TItem>.IsReadOnly

        {

            get { return false; }

        }

 

        bool ICollection<TItem>.Remove(TItem item)

        {

            if (item == null)

            {

                return false;

            }

            if (_itemsMap.ContainsKey(item.Key) == true)

            {

                _itemsMap.Remove(item.Key);

 

                _items.Remove(item);

 

                return true;

            }

            return false;

        }

 

        #endregion

 

        #region IEnumerable<TItem> Members

 

        IEnumerator<TItem> IEnumerable<TItem>.GetEnumerator()

        {

            return _items.GetEnumerator();

        }

 

        #endregion

 

        #region IEnumerable Members

 

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()

        {

            return _items.GetEnumerator();

        }

 

        #endregion

    }

}

Enjoy!

Posted: Aug 18 2008, 04:36 AM by egady | with no comments
תגים:,

Create a WPF UserControl Library Project

Create a WPF UserControl Library Project

In Visual Studio 2008 you can create a Windows Presentation Foundation (WPF) UserControl Library Project, and developing your own controls.

WPF UserControl Library Project

Then, you need an application to run those controls, I will show here a static way to run one of the controls.

Add WPF Application Project to the solution, and set a reference to the UserControl Library.

WPF Apllication Project

App.xaml

Your App.xaml is like the following xaml:

<Application x:Class="MyApp.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    StartupUri="Window1.xaml">

    <Application.Resources>

 

    </Application.Resources>

</Application>

Windows1.xaml

Go to Windows1.xaml and add a reference to your UserControl Library, and then add a namespace directive (I used 'my') into your Windows1.xaml Page.

<Window x:Class="MyApp.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:my="clr-namespace:MyComponentsNS;assembly=MyComponents"

    Title="Window1" Height="300" Width="300">

    <my:MyUserControl></my:MyUserControl>

</Window>


Then, you can use your own UserControl.

Conclusion

This is a static way to upload user control, which stored in different assembly. Next post I will show how to do it dynamically.

Technorati Profile

Develop Facebook Application using Facebook Developer Toolkit

Develop Facebook Application using Facebook Developer Toolkit

Lets see how it easy to create new application in Facebook, using Facebook Developer Toolkit.

Create new Facebook Application 

Add the Developer Application to your account at Facebook.

Now you can set up a new application:

 

Set up  new Facebook Application

Facebook will provide you API Key and Secret Key you will use later.

Set up the following properties: 

  • FBML/iframe - iframe
  • Application Type - Website
  • Callback URL - <Your callback URL, see next step> for example: http://localhost:3243/Facebook/Default.aspx

Create ASP.NET Web Site

Create in Visual Studio new ASP.NET Web Site.

After downloading binaries of Facebook Developer Toolkit, add to your project references to:

  • Facebook.dll
  • Facebook.WebControls.dll 

Go to your application in Facebook and setup the Callback URL to the URL of the Default.aspx page.

It is ok to put for now localhost.

Go to the code of Default.aspx.cs and insert the following sample code:

public partial class _Default : System.Web.UI.Page

{

    Facebook.Components.FacebookService m_fbService = new Facebook.Components.FacebookService();

 

    private const String FACEBOOK_API_KEY = "<YOUR API KEY>";

    private const String FACEBOOK_API_SECRET = "<YOUR API SECRET>";

 

    protected void Page_Load(object sender, EventArgs e)

    {

        m_fbService.ApplicationKey = FACEBOOK_API_KEY;

        m_fbService.Secret = FACEBOOK_API_SECRET;

        m_fbService.IsDesktopApplication = false;

 

        String sessionKey = Session["facebook_session_key"] as String;

        String userId = Session["facebook_userId"] as String;

 

        String authToken = Request.QueryString["auth_token"];

 

        if (!String.IsNullOrEmpty(sessionKey))

        {

            m_fbService.SessionKey = sessionKey;

            m_fbService.UserId = userId;

        }

        else if (!String.IsNullOrEmpty(authToken))

        {

            m_fbService.CreateSession(authToken);

 

            Session["facebook_session_key"] = m_fbService.SessionKey;

            Session["facebook_session_key"] = m_fbService.UserId;

            Session["facebook_session_expires"] = m_fbService.SessionExpires;

        }

        else

        {

            Response.Redirect(@"http://www.Facebook.com/login.php?api_key=" + m_fbService.ApplicationKey + @"&v=1.0");

        }

        if (!IsPostBack)

        {

            Collection<Facebook.Entity.User> friends = m_fbService.GetFriends();

        }

    }

}

 

Now, you can test your application. This is a very simple application, and I'm going to add to this application some features in future posts.

Enjoy! 

 

 

To JSON or not to JSON?

To JSON or not to JSON?

I want to introduce some performance testing about DataContractJsonSerializer against DataContractSerializer.

But first, I want to explain what is JSON and DataContractJsonSerializer?

What is JSON?

JSON (JavaScript Object Notation) is a lightweight syntax for representing data that enabling fast exchanges of small amount of data between client browsers and AJAX-enabled Web services.

JSON encodes data using subset of the JavaScript object literals, and it easier to "parse" for JavaScript client code, and used as alternative to XML in AJAX applications.

The following sample illustrates how easy you can parse JSON in JavaScript, using 'eval' method:

var jsonText = “someVar = { 'color' : 'blue' }”;

eval( ‘(‘ + jsonText + ‘)’ );

alert(someVar.color);

DataContractJsonSerializer

With DataContractJsonSerializer introduced with WCF 3.5 you can serialize instance of .NET type into a JSON document, and de-serialize JSON document into an instance of a .NET type.

.NET Framework 3.5 include reach support of JSON in WCF. You can specify for each method if it accept/return JSON format or XML.

The DataContractJsonSerializer can be plugged by using WebScriptEnablingBehavior or by using WebHttpBehavior.

For WebScriptEnablingBehavior see the following post about WCF and ASP.NET AJAX Integration.

JsonReaderWriterFactory

WCF processes JSON messages using mapping between JSON data and the XML info-set. For that WCF use the XmlDictionaryReader and XmlDictionaryWriter produced by the JsonReaderWriterFactory, which provide an XML API over JSON.

The following JSON object:

{ “product” : “pencil”, “price” : 12 }

Translates into the following XML info-set:

<root type=“object”>

    <product type=“string”>pencil</product>

    <price type=“number”>12</price>

</root>

The Performance Test

I'm including two tests:

1) One customer with simple data.

  JSON XML JSON / XML
CustomerList Length 275 471 0.5838
Serialization Time 0.18 0.02 9
Deserialization Time 0.3 0.1 3

2) List of 13 Customers, each contains 20 sales orders, each contains 75 sales order items.

  JSON XML JSON / XML
CustomerList Length 1587031 3007061 0.5277
Serialization Time 294.3 181.4 1.6223
Deserialization Time 416 323 1.2879

Conclusion

It seems that DataContractJsonSerializer doesn't implemented in a way that adhere to the JSON as a lightweight syntax advantages over XML. But, the test should be completed, and with the end-to-end results, by parsing the data also at the browser side (JavaScript), the final results should be different.

kick it on DotNetKicks.com

Technorati Tags: ,,
Posted: Jun 15 2008, 10:19 PM by egady | with 4 comment(s)
תגים:, ,

REST Friendly URLs

REST Friendly URLs

Lest say you have an articles site, which have:

  • Category: credit-card
  • Sub Category: student
  • Article Id: students-heed-parents-on-credit-card-advice

The following two samples describes the difference between friendly URLs and Dirty URLs:

Dirty URLs

http://.../article/Article.aspx?categoryId=credit-card&subCategoryId=student&articleId=student-article

http://.../Category.aspx?categoryId=credit-card

http://.../SubCategory.aspx?categoryId=credit-card&subCategoryId=student

Friendly URLs

http://.../article/credit-card/student/student-article

http://.../category/credit-card

http://.../category/credit-card/student

Why Does URL Rewriting Matter?

There are some reasons why me matter about rewriting URLs to get a clean version of them:

  • Bookmaking - The URLs are part of your API in REST world, and such, client may bookmarks them or have some client programs that works with your API links. Your goal is to stay with the same URL no matter if you changing tomorrow your technology.
  • Usability - Friendly URLs are easy to remember and provides cues to the user about the resource itself.
  • Hide implementation details - The main reason is abstraction. The user doesn't require to know how I implemented it.
  • Security - The query string which follow the question mark (?) is often modified by hackers.
  • Logical URLs - If you have a site with 400,000 pages, it is not easy to maintain all of them, for example, you need to add some script for all pages..., using logical you can use only few physical pages to serve all the pages Logical URLs means that any URL in your site represents resource which is not physical but logical.
  • Search Engine Optimization (SEO) - When search engine gets URL which imply that the underlying site is dynamic, and use query parameters, it treats to him different than he gets a friendly URL.

URL Rewriting with IIS 7.0

Intercepting request with IIS 7.0 is very easy:

  • Implement HttpModule
  • Configure it in Web.Config

The following sample is show how to remove '.svc' extension from WCF service hosted in IIS:

 

    public void Init(HttpApplication app)

    {

        app.BeginRequest += delegate

        {

            HttpContext ctx = HttpContext.Current;

            String path = ctx.Request.AppRelativeCurrentExtensionFilePath;

            // …

            ctx.RewritePath(path + “.svc”, …);   

        }

    }

URL Rewriting with UrlRewriter.NET

    <section

      name="rewriter"

      requirePermission="false"

      type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter"/>

  </configSections>

 

      <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/>

    </httpModules>

 

      <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule"/>

    </modules>

  • Define your mapping:

  <rewriter>

    <rewrite

        url="~/article/(.+)/(.+)/(.+)"

        to="~/Article.aspx?categoryId=$1&amp;subCategoryId=$2&amp;articleId=$3"/>

    <rewrite

        url="~/category/(.+)/(.+)"

        to="~/SubCategory.aspx?categoryId=$1&amp;subCategoryId=$2"/>

    <rewrite

        url="~/category/(.+)"

        to="~/Category.aspx?categoryId=$1"/>

  </rewriter>

</configuration>

  • The source code for Article.aspx.cs is show in the following sample:

 

        protected void Page_Load(object sender, EventArgs e)

        {

            ASP.article_aspx page = sender as ASP.article_aspx;

            if (page == null)

            {

                return;

            }

     

            String categoryId = page.ApplicationInstance.Request.Params["categoryId"];

            String subCategoryId = page.ApplicationInstance.Request.Params["subCategoryId"];

            String articleId = page.ApplicationInstance.Request.Params["articleId"];

Conclusion

Friendly URLs are simple to implements, and have a big rewards on this few additional lines of code. I show here two methods to use it, there are few more (ISAPI filters on IIS 6.0, HttpContext.RewritePath() in ASP.NET), but I wanted to concentrate on the better approaches.

With Friendly URLs your site links (and API) are clean, easy to remember, SEO friendly, and has abstraction level.

kick it on DotNetKicks.com

Technorati Tags: ,,,
Posted: Jun 09 2008, 02:31 PM by egady | with 5 comment(s) |
תגים:, , ,

Presentation Tips

Presentation Tips

After my first presentation in user groups: WCF 3.5 REST Presentation I put some tips and lessons I had, so new presenters can used.

  1. Projector verification - If you can, verify a week before the presentation that your laptop works with the projector, or at least check if your laptop brand have problems with the specific projector.
  2. Internet verification - If your presentation requires Internet, verify that you can access the internet, usually it required special request some days before.
  3. Portable demos - Put all your demos also in a flash disk, so in case of problems you can move them quickly to another computer.
  4. Interoperable demos - All your demos should be able to run in minimal environment, which means avoid database usage if you can.
  5. Know your audience needs - Prepare the content for the audience needs.
  6. Short slides - Each slide should contain no more than 3-4 lines.
  7. Prepare hidden slides - Or additional notes (do not read from them!!) since when you look on a slide with 3 lines, you may forget some additional issues you want to talk about.
  8. Manage your time wisely - Prepare by talking about each issue and measure the time each issue take, so you promise you have enough to talk. It is ok to finish before time, just be aware to it.
  9. Practice at home - Before the real presentation, you should practice your speech in front of some friends at home, prefer those with appropriate background so they can ask questions, write the question, and prepare to them. If they haven't appropriate background, it is still better than nothing.
  10. Review your presentation - Send your presentation to friends for review, it can help to see thinks you didn't see. Also you should spend time to review the presentation design and flow.
  11. Time to arrive - Arrive at least one hour before the presentation to setup the projector and internet, and verify all the demos works appropriately.
  12. Master your presentation - Prepare to any question.
  13. Presentation prepared - Finish the presentation and demos some days before the date, so you can practice speech.
  14. Listen to the audience - Be aware when they don't understand something, boring, etc.

Do you have something to share from your experience?

WCF and ASP.NET AJAX Integration

WCF and ASP.NET AJAX Integration

This post is part of WCF REST Presentation I show last week at Microsoft. 

I played with the WCF and ASP.NET AJAX integration, and created a sample web site which by can integrate WCF service with Microsoft Virtual Earth.

Virtual Earth: Starbucks Manhattan 

The Service Contract

The following contract is simple service contract with one method GetLocation(). The namespace "Sample.Services" will be used later as a prefix to the generated proxy.

AspNetCompatibilityRequirementsMode allows the service to use ASP.NET features, such as accessing HttpContext object or identity impersonation.

[ServiceContract(Namespace = "Sample.Services")]

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

public class MapService

{

    [OperationContract]

    public Location GetLocation(Target target)

    {       

        Double latitude = 0;

        Double longitude = 0;

        if (target.Name == "Starbucks Manhattan")

        {

            latitude = 40.70456;

            longitude = -74.01317;

        }

        Location location = new Location

        {

            Latitude = latitude,

            Longitude = longitude

        };

        return location;

    }

}

[DataContract]

public class Location

{

    [DataMember]

    public Double Latitude

    {

        get;

        set;

    }

    [DataMember]

    public Double Longitude

    {

        get;

        set;

    }

}

[DataContract]

public class Target

{

    [DataMember]

    public String Name

    {

        get;

        set;

    }

}

The Script

The interesting point here is how you access the service itself - by adding the namespace prefix (if not exist use default Tempuri.org).

You can also notice how I'm sending a complex parameter 'target' which is not a basic type, but complex - I use JSON directly .

var map;
var index = 0;


function LoadMap()
{   
    map = new VEMap('VEMap');
    map.LoadMap();   
}


function WebServiceCallBack(response)
{    
    AddPushPin(response);                                     
}

function AddPushPin(point)
{      
    var pin = new VEPushpin(
        index,
        new VELatLong(point.Latitude, point.Longitude),
        null,
        point.Name,
        point.Description); 
        index++;
    map.AddPushpin(pin);        
    map.PanToLatLong(new VELatLong(point.Latitude, point.Longitude));
}

function OnGetTarget()
{
    var target = { "Name" : $get("target").value }; 
    Sample.Services.MapService.GetLocation(target, WebServiceCallBack, OnError);
}

function OnError(result)
{
    alert(result.get_message());
}

Proxy Generation

Try the following URL and you will get the proxy itself:

http://localhost:49814/VirtualEarth/MapService.svc/js

Notice that the proxy created with static methods with the same signature as the methods on the service itself, and as additional, adds callback, error handler and a user context.

Type.registerNamespace('Sample.Services');
Sample.Services.MapService=function() {
Sample.Services.MapService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
Sample.Services.MapService.prototype={
_get_path:function() {
var p = this.get_path();
if (p) return p;
else return Sample.Services.MapService._staticInstance.get_path();},
GetLocation:function(target,succeededCallback, failedCallback, userContext) {
return this._invoke(this._get_path(), 'GetLocation',false,{target:target},succeededCallback,failedCallback,userContext); }}
Sample.Services.MapService.registerClass('Sample.Services.MapService',Sys.Net.WebServiceProxy);
Sample.Services.MapService._staticInstance = new Sample.Services.MapService();
Sample.Services.MapService.set_path = function(value) { Sample.Services.MapService._staticInstance.set_path(value); }
Sample.Services.MapService.get_path = function() { return Sample.Services.MapService._staticInstance.get_path(); }
Sample.Services.MapService.set_timeout = function(value) { Sample.Services.MapService._staticInstance.set_timeout(value); }
Sample.Services.MapService.get_timeout = function() { return Sample.Services.MapService._staticInstance.get_timeout(); }
Sample.Services.MapService.set_defaultUserContext = function(value) { Sample.Services.MapService._staticInstance.set_defaultUserContext(value); }
Sample.Services.MapService.get_defaultUserContext = function() { return Sample.Services.MapService._staticInstance.get_defaultUserContext(); }
Sample.Services.MapService.set_defaultSucceededCallback = function(value) { Sample.Services.MapService._staticInstance.set_defaultSucceededCallback(value); }
Sample.Services.MapService.get_defaultSucceededCallback = function() { return Sample.Services.MapService._staticInstance.get_defaultSucceededCallback(); }
Sample.Services.MapService.set_defaultFailedCallback = function(value) { Sample.Services.MapService._staticInstance.set_defaultFailedCallback(value); }
Sample.Services.MapService.get_defaultFailedCallback = function() { return Sample.Services.MapService._staticInstance.get_defaultFailedCallback(); }
Sample.Services.MapService.set_path("/VirtualEarth/MapService.svc");
Sample.Services.MapService.GetLocation= function(target,onSuccess,onFailed,userContext) {Sample.Services.MapService._staticInstance.GetLocation(target,onSuccess,onFailed,userContext); }
var gtc = Sys.Net.WebServiceProxy._generateTypedConstructor;
if (typeof(Target) === 'undefined') {
var Target=gtc("Target:http://schemas.datacontract.org/2004/07/
Target.registerClass('Target');
}
if (typeof(Location) === 'undefined') {
var Location=gtc("Location:http://schemas.datacontract.org/2004/07/
Location.registerClass('Location');
}

The ASP.NET Page

<html xmlns="http://www.w3.org/1999/xhtml >
    <head id="Head1" runat="server">
        <title></title>
    </head>
    <body onload="LoadMap();">

        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Scripts>
                    <asp:ScriptReference Path="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5 />
                    <asp:ScriptReference Path="mapscripts.js" />
                </Scripts>
                <Services>
                    <asp:ServiceReference Path="MapService.svc"  />
                </Services>
            </asp:ScriptManager>
            <div style='width: 800px; height: 500px; position: relative; overflow: hidden;' id='VEMap'></div>   

            Enter target: <input type="text" id="target" />

            <input type="button" value="get target" onclick="OnGetTarget()" /><br />
            <br />
        </form>
    </body>
</html>

The Service File

The WebScriptServiceHostFactory adds ASP.NET AJAX endpoint the the service, and all of this without a line of configuration!!

When you specify the WebScriptServiceHostFactory, it creates a ServiceHost with the appropriate binding and behavior for integration with ASP.NET AJAX.

<%@ ServiceHost Language="C#" Debug="true" Service="MapService" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>

Conclusion

To summarize the WCF and ASP.NET AJAX Integration:

  • Full support in client stack
  • Provides proxy generation
  • Supports GET and POST only
  • Does not support UriTemplates
  • No configuration using WebScriptServiceHostFactory
  • And finally, works in ASP.NET medium trust

The source code of WCF and ASP.NET AJAX Integration.

WCF 3.5 REST Presentation

WCF 3.5 REST Presentation

Hi,

I want to thank to C* User Group, Microsoft people and all of those who come to the presentation yesterday at Microsoft.

It was pleasurable and very beneficial, I study a lots from it, and I highly recommend for anyone who hesitated.

I'm attaching here the presentation, and I will post the code later.

WCF-REST.pptx

WCF and ASP.NET AJAX Integration

REST Friendly URLs

Thanks,

Gady.

Posted: May 22 2008, 10:32 AM by egady | with 2 comment(s)
תגים:,

Creating RESTful Web Services with WCF

Hi,

I'm giving a presentation tomorow about the "New HTTP Programming Model in WCF 3.5". I will talk about RESTful services, show demos on WCF, and using some known REST API's.

Some teasers:

Microsoft Virtual Earth Facebook

 

Attached below the invitation, hope to see you there.

Gady.

 

 

 

 

Israel Visual C* Users Group May Meeting

Date:    Wednesday, May 21, 17:00 - 20:00

Place:   Microsoft Israel 

            Hapnina 2 (Amdocs Building)

            Raanana

+972 (9) 762-5100         

 

 

Topic: “Creating RESTful Web Services with WCF

Lecturer: Gady Elkarif, SAP Labs, Israel

 

Creating RESTful Web Services with WCF

REST stands for Representational State Transfer; a term coined by one of the original authors of the HTTP protocol, Roy Fielding, in his 2000 doctoral dissertation. This session will show the power and productivity of WCF 3.5, demonstrating the new Web-centric features of WCF in the .NET Framework 3.5. The session will focus on the new web programming model features of WCF, enabling you to develop "RESTful" web services. The session starts with a brief overview of what does it mean to be "RESTful", then moves on to the new HTTP web programming model in WCF, including easy-to-use HTTP programming model, JavaScript Object Notation (JSON) messaging capabilities, and a new syndication API that makes it easy to create and consume syndicated content. Finally, the session will end with some advanced topics on developing REST API with WCF and a demonstration of using real commercial REST API (hosting a Silverlight application in Facebook).

Posted: May 20 2008, 02:12 PM by egady | with 1 comment(s)
תגים:,
More Posts Next page »