The problem : Creating WCF proxy in Silverlight without using the add service reference and it’s auto generated code
It was a debate that whether we can call a WCF service from Silverlight without using “Add Service Reference” menu item.In WPF or in the other .Net environments it is easy.We just need to refer the contracts dll and write a class which inherits from ClientBase.But this is Silverlight - A different runtime.
A Normal WCF service reference with all the generated code files
There were 3 opinions.Not at all possible,Possible with less amount of code,Possible if we create all those classes by our own.Just avoid the last one because that doesn’t give us any benefit as it is just making the process manual.
One of my Colleagues started research on that and was able to achieve the same.I am just sharing the idea.
Solution : We can achieve the same using contract interface,proxy class and a custom eventargs class
First of all there are no changes at the server side.Only 3 types we are going to write at client side which will be present in the reference.cs file if you create the proxy using “Add Service Reference” Dialog.
There will be a question for sure.Why are we writing the code which is being auto generated ? Why don’t we create a reference using the dialog and copy paste the reference.cs code?
The answer for both the questions is same.You can create reference using the dialog and get the code from reference.cs.That is enough.
Advantages
- Can avoid huge amount of code which is auto generated.
- This is acting as a separate layer and can encapsulate operations here in future.
Implementation steps
Lets take example of implementing a DataService with one method GetData which returns a string.Don’t bother about the server side.Use the same.Below are the steps to perform at client side ie Silverlight side.
- Create interface IDataService
- Decorate with ServiceContract attribute.
- Add method BeginGetData.Decorate it with OpertionContract and Set AsyncPattern to True.
- Add Method EndGetData.
Imports System.ServiceModel
<ServiceContract()> _
Public Interface IDataService
<OperationContract(AsyncPattern:=True)> _
Function BeginGetData(ByVal callback As System.AsyncCallback, ByVal asyncState As Object) As System.IAsyncResult
Function EndGetData(ByVal result As System.IAsyncResult) As String
End Interface
- Create eventArgs class deriving from System.ComponentModel.AsyncCompletedEventArgs
- Add required properties to pass values.
Public Class GetDataCompletedEventArgs
Inherits System.ComponentModel.AsyncCompletedEventArgs
Private results() As Object
Public Sub New(ByVal results() As Object, ByVal exception As System.Exception, ByVal cancelled As Boolean, ByVal userState As Object)
MyBase.New(exception, cancelled, userState)
Me.results = results
End Sub
Public ReadOnly Property Result() As String
Get
If Me.results IsNot Nothing Then
Return CType(Me.results(0), String)
End If
Return Nothing
End Get
End Property
End Class
- Create class DataServiceProxy derived from ClientBase which Implements IDataService.Write constructors.Implement methods.Write delegates and event which communicate back to the caller.
Public Class DataServiceProxy
Inherits ClientBase(Of IDataService)
Implements IDataService
#Region " Constructors"
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal endpointConfigurationName As String)
MyBase.New(endpointConfigurationName)
End Sub
Public Sub New(ByVal endpointConfigurationName As String, ByVal remoteAddress As String)
MyBase.New(endpointConfigurationName, remoteAddress)
End Sub
Public Sub New(ByVal endpointConfigurationName As String, ByVal remoteAddress As System.ServiceModel.EndpointAddress)
MyBase.New(endpointConfigurationName, remoteAddress)
End Sub
Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, ByVal remoteAddress As System.ServiceModel.EndpointAddress)
MyBase.New(binding, remoteAddress)
End Sub
#End Region
#Region "GetData"
Private onBeginGetDataDelegate As BeginOperationDelegate
Private onEndGetDataDelegate As EndOperationDelegate
Private onGetDataCompletedDelegate As System.Threading.SendOrPostCallback
Public Event GetDataCompleted As System.EventHandler(Of GetDataCompletedEventArgs)
Public Function BeginGetData(ByVal callback As System.AsyncCallback, ByVal asyncState As Object) As System.IAsyncResult Implements ServiceContracts.IDataService.BeginGetData
Return MyBase.Channel.BeginGetData(callback, asyncState)
End Function
Public Function EndGetData(ByVal result As System.IAsyncResult) As String Implements ServiceContracts.IDataService.EndGetData
Return MyBase.Channel.EndGetData(result)
End Function
Private Function OnBeginGetData(ByVal inValues() As Object, ByVal callback As System.AsyncCallback, ByVal asyncState As Object) As System.IAsyncResult
'Dim engID As String = CType(inValues(0), String)
'Dim libraryID As String = CType(inValues(1), String)
'Dim folderName As String = CType(inValues(2), String)
'Dim parentFolder As PathInfo = CType(inValues(3), PathInfo)
'Dim folderGeneralProperties As FolderGeneralProperties = CType(inValues(4), FolderGeneralProperties)
'Dim additionalProperties As System.Collections.Generic.Dictionary(Of String, String) = CType(inValues(5), System.Collections.Generic.Dictionary(Of String, String))
Return CType(Me, IDataService).BeginGetData(callback, asyncState)
End Function
'Private Function GetData() As String Implements IDataService.GetData
'Return MyBase.Channel.GetData()
'End Function
Private Function OnEndGetData(ByVal result As System.IAsyncResult) As Object()
Dim retVal As String = CType(Me, IDataService).EndGetData(result)
Return New Object() {retVal}
End Function
Private Sub OnGetDataCompleted(ByVal state As Object)
'If Not (GetDataCompleted Is Nothing) Then
Dim e As InvokeAsyncCompletedEventArgs = CType(state, InvokeAsyncCompletedEventArgs)
RaiseEvent GetDataCompleted(Me, New GetDataCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState))
'End If
End Sub
Public Overloads Sub GetDataAsync()
If (Me.onBeginGetDataDelegate Is Nothing) Then
Me.onBeginGetDataDelegate = AddressOf Me.OnBeginGetData
End If
If (Me.onEndGetDataDelegate Is Nothing) Then
Me.onEndGetDataDelegate = AddressOf Me.OnEndGetData
End If
If (Me.onGetDataCompletedDelegate Is Nothing) Then
Me.onGetDataCompletedDelegate = AddressOf Me.OnGetDataCompleted
End If
MyBase.InvokeAsync(Me.onBeginGetDataDelegate, New Object() {}, Me.onEndGetDataDelegate, Me.onGetDataCompletedDelegate, Nothing)
End Sub
#End Region
End Class
Uploaded a sample which does the same.