WCF Services in ASP.NET websites
WCF Introduction
WCF is unifying programming model. Single approach to writing services and unifying technologies such as web services (ASMX), .NET remoting, message queues (MSMQ), Enterprise Services (COM+) and Web Services Enhancements (WSE).
WCF is message based communications between endpoints.
Write service and then attach one (or more) endpoints.
Endpoint defines location to which messages are sent or received.
Location includes address, binding and contract:
- A is for address - a URI defining location of service. Each endpoint must have unique address.
- B is for binding - defines how service communicates via protocols such as HTTP, TCP, MSMQ, HTTP, etc. Protocol referred to as binding transport. At a minimum must define transport, but can include encoding, security, etc.
- C is for contract - public definition (or interface) of service. Defines namespace, how message sent, callbacks, contract items, etc. Multiple contracts in WCF - e.g. service, operation, message, fault, data, etc. Contracts indicate to client how message should be constructed.
After defined and configured WCF service it must be hosted. Several options for this, but concentrate on IIS and ASP.NET here.
WCF Architectural Layers
- Contract Layer - defines contract service exposed to clients. Includes messages for calling operations, receiving results and managing errors. Includes endpoint information, e.g. contract may indicate HTTP with binary encoding.
- Runtime Layer - controls how service is executed and message body processed. Can configure to support transactions, handle concurrency and generate error information. For example throttling to indicate how many messages service can process, instance functionality to control how many service instances created, etc.
- Messaging Layer - the WCF channel stack in terms of transport (HTTP, named pipes, TCP, etc.) and protocol (handle reliability and security).
- Hosting Layer - defines executable file that runs the service. Can be self hosted, or hosted by IIS, WAS, a Windows Service or COM+. Host choice depends on client access, scalability, reliability and need for other host services (e.g. ASP.NET).
WCF Service with ASP.NET
Follow these steps to create WCF service:
- Define service contract
- Implement service contract
- Configure service endpoints
- Host service
- Reference and call service from client
Define service contract by defining interface and decorating it with attributes - typically:
- ServiceContract - indicates interface is WCF service. Has parameters indicating SessionMode, namespace, name of contract, return contract (CallbackContract) on a 2-way contract, etc.
[ServiceContract]
public interface IShipperService
{
[OperationContract]
Shipper GetShipper(int shipperId);
[OperationContract]
Shipper SaveShipper(Shipper shipper);
}
- OperationContract - marks methods within interface as service operations. Parameters define settings such as whether a reply is generated (IsOneWay), security (ProtectionLevel) and async support (AsyncPattern).
- DataContract - Marks types (classes, enums, structs) as participating in WCF serialization.
- DataMember - Mark individual fields and properties for serialization. [DataContract] public class Shipper { [DataMember] public int ShipperId {get; set;} }
WCF Service Templates
Visual Studio provides WCF Service Application project template.
The IService1.cs file defines an interface to be used as the service contract.
The Service1.svc is a webpage that provides URL for service. Uses @ ServiceHost directive to indicate page is a service. Code behind file implements the service.
Automatically configured to be hosted by IIS - see <system.serviceModel> section of web.config.
Can also add WVF service to existing website via the Add New Item dialogue.
Consuming WCF Service
Right click website and select "Add Service Reference" and navigate to .svc URL for web service.
Namespace in dialogue defines name for generated proxy class.
Reference.cs contains the actual proxy code, rest of files used when working with webservice.
Will also generate appropriate endpoint information and write to web.config file, e.g.:
<client>
<endpoint address="http://localhost/ShipperService.svc" binding="basicHttPBinding" bindingConfiguration="BasicHttpBinding_IShipperService", contract="ShipperServiceRef.IShipperService" name="BasicHttpBinding_IShipperService" /)
</client>
Calling WCF Service via AJAX (REST and JSON)
WCF is mechanism to define endpoints, binding and contracts so supports many message types and protocols, e.g. representational state transfer (REST) and JavaScript Object Notation (JSON).
Programming AJAX became easier with a simple service (REST) based on simple message format (JSON).
REST web service responds to basic HTTP requests, e.g. GET, POST, PUT, DELETE. Clients call in same way they would a web page. REST service does not require knowledge of XML schema used to call service, instead simply uses text-based responses (usually JSON formatted data).
REST does not use SOAP. Many service based security models are based on SOAP. If data security is important use HTTPS between client and server.
Example of JSON formatted message:
{
"productName": "Computer Monitor",
"price": "229.00"
}
Creating WCF Service using REST and JSON
AJAX-WCF template available via "Add New Item" | AJAX-Enabled WCF Service template.
[ServiceContract(Namespace="PricingServices")]
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirements.Allowed)]
public class PricingService
{
[OperationContract]
[WebInvoke]
public double CalculatePrice("string itemId, string shipToPostalCode)
{
}
}
The WebInvoke attribute indicates method is called by HTTP request.
WebInvoke methods are called by HTTP POST. Use when sending data to server or don't want request to be cached.
WebGet methods are called by HTTP GET. Used to return static data that can be cached.
The web.config will be modified so that the binding is set to webHttpBinding - indicates service called via HTTP (not SOAP).
<endpoint address="" behaviorConfiguration="PricingServiceAspNetAjaxBehavior" binding="webHttpBinding" contract="PricingService" />
The endpointBehavior has an enableWebScript element appended to it indicating that the end point is a RESTful using JSON data format.
<endpointBehaviors>
<behavior name="PricingServiceAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
Calling JSON based WCF Service from AJAX
ScriptManager control allows a service reference to be set to RESTful WCF service.
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="PricingService.svc"/>
</Services>
</asp:ScriptManager>
Then use script block on page to call proxy generated by service reference, passing in callback method if required.
<script language="javascript" type="text/javascript">
function ButtonCalculate_onclick() {
var service = PricingServices,PricingService();
service.CalculatePrice(document.forms[0].TxtBoxProduct.value, document.forms[0].TextBoxPostCode.value, onSuccess, null, null);
}
onSuccess(result) {
LabelPrice.innerText = result;
}
</script>
WCF Data Services
Can expose and work with data via Open Data Protocol (OData).
Exposed over REST-based services.
Follow these steps:
- Define data model using Entity Data Model (EDM) via ADO.NET Entity Data Model template.
- Create data service using WCF Data Services template.
- Add code to data service to access the EDM, e.g. to expose the "Customer" table: public static void InitializeService(DataServiceConfiguration config) { config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.2; config.SetEntityAccessRule("Customer", EntitySetRights.AllRead | EntitySetRights.AllWrite);
- Create client to access data service.
- Add service reference to client - generates WCF proxy for calling service.
- Write code to work with exposed data - often down via LINQ. Uri svcUri = new Uri("http://localhost/WcfDataSrv/NwdDataService.svc"); NwdEntitiesSrv.NewEntities nwd = new NwdEntitiesSrv.NewEntities(svcUri); DataServiceQuery<NwdEntitiesSrv.Customer> q = nwd.Customers; this.GridViewCustomers.DataSource = q; this.GridViewCustomers.DataBind();