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:
Next, add new Service Library (MySPServicesLibrary) project to the ASP.NET Application:
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:
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
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:
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>
One of the implications of this implementation is that master page is just another control in your page, which means it accessible in code:
void Page_Load(object sender, EventArgs e)
{
HtmlForm form = Master.FindControl("form1") as HtmlForm;
if (form != null)
{
}
}
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:

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
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.
In the Create or Extend Web Application page, enter the user name and password, and click OK.
In the Application Created page press on Create Site Collection link.
In the Create Site Collection, select title, URL and site template. Provide also user name and press OK.
Verify your site collection was successfully created in the following URL:
http://myhost:port/sites/MySiteCollection

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.
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.
Press on “Create Hierarchies” operation and go to the site collection home page, this is the result I get:
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:
If you add and publish a new page in the English site, it will duplicated to the other sites in the hierarchy.
Technorati Tags:
SharePoint 12
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
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:
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:
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:
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);
}
}
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!
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.
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.
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
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:
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?
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.
Technorati Tags:
WCF 3.5,
AJAX,
JSON
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>
<rewriter>
<rewrite
url="~/article/(.+)/(.+)/(.+)"
to="~/Article.aspx?categoryId=$1&subCategoryId=$2&articleId=$3"/>
<rewrite
url="~/category/(.+)/(.+)"
to="~/SubCategory.aspx?categoryId=$1&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.
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.
- 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.
-
Internet verification - If your presentation requires Internet, verify that you can access the internet, usually it required special request some days before.
-
Portable demos - Put all your demos also in a flash disk, so in case of problems you can move them quickly to another computer.
-
Interoperable demos - All your demos should be able to run in minimal environment, which means avoid database usage if you can.
-
Know your audience needs - Prepare the content for the audience needs.
-
Short slides - Each slide should contain no more than 3-4 lines.
-
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.
-
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.
-
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.
-
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.
-
Time to arrive - Arrive at least one hour before the presentation to setup the projector and internet, and verify all the demos works appropriately.
-
Master your presentation - Prepare to any question.
-
Presentation prepared - Finish the presentation and demos some days before the date, so you can practice speech.
-
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
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.
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
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.
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:
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).
More Posts
Next page »