BeginFetch does not result in DataPortal_Fetch in Silverlight

BeginFetch does not result in DataPortal_Fetch in Silverlight

Old forum URL: forums.lhotka.net/forums/t/7811.aspx


GregDobbs posted on Sunday, October 18, 2009

I am having no luck in discovering why a Silverlight partial class is unable to execute a DataPortal_fetch on the server.

All service references are set properly. Yet, when BeginFetch is executed, it results in a "DataPortal_fetch Not Implemented" exception.

What is required to get the Silverlight client to recognize the server-side partial class???? What can cause this error???

I would love it if someone could intentionally break one of their applications to reproduce this error and then tell me what they did to produce this exception. I've had no responses to my previous posts on this issue.

Here are the two classes:


Server-side class:

Imports System
Imports System.Security.Principal
Imports System.Collections.Generic
Imports System.Runtime.Serialization
Imports System.Data.SqlClient
Imports Csla
Imports Csla.Core
Imports Csla.Data
Imports Csla.Security
Imports Csla.Serialization
Imports Csla.Core.FieldManager
Imports Csla.DataPortalClient
Namespace Security

[Serializable()] _
Public Class desIdentity
Inherits ReadOnlyBase(Of desIdentity)
Implements IIdentity

Private mRoles As New List(Of String)

Friend Function IsInRole(ByVal role As String) As Boolean
Return mRoles.Contains(role)
End Function


#Region " Factory Methods "

Friend Shared Function GetIdentity(ByVal entityid As String, ByVal username As String, ByVal password As String) As desIdentity
Return DataPortal.Fetch(Of desIdentity)(New LoginCriteria(entityid, username, password))
End Function

#End Region

#Region " Data Access "

Public Overloads Sub DataPortal_Fetch(ByVal criteria As LoginCriteria)
Try
Using cxmgr As Csla.Data.ConnectionManager(Of SqlConnection) = Csla.Data.ConnectionManager(Of SqlConnection).GetManager("clientNet", True)
Dim cn As SqlConnection = cxmgr.Connection
Using cm As SqlCommand = cn.CreateCommand()
cm.CommandText = "admin_CSLALogin"
cm.CommandType = CommandType.StoredProcedure
cm.Parameters.AddWithValue("@EntityID", criteria.EntityID)
cm.Parameters.AddWithValue("@UserName", criteria.UserName)
cm.Parameters.AddWithValue("@Password", criteria.Password)
Using dr As SafeDataReader = New SafeDataReader(cm.ExecuteReader())
If dr.Read() Then

LoadProperty(IsAuthenticatedProperty, True)
LoadProperty(CSLAUserKeyProperty, dr.GetInt32("CSLAUserKey"))
LoadProperty(NameProperty, criteria.UserName)
LoadProperty(FirstNameProperty, dr.GetString("FirstName"))
LoadProperty(LastNameProperty, dr.GetString("LastName"))
LoadProperty(FullNameProperty, dr.GetString("FullName"))
LoadProperty(EntityNameProperty, dr.GetString("EntityName"))
LoadProperty(EntityNameProperty, dr.GetString("EntityName"))
LoadProperty(LoginTypeProperty, dr.GetString("LoginType"))
LoadProperty(ResultMessageProperty, "Loaded Identity for " & criteria.UserName)

If dr.NextResult Then
While dr.Read
mRoles.Add(dr.GetString(0))
End While
End If

Else
LoadProperty(IsAuthenticatedProperty, False)
LoadProperty(CSLAUserKeyProperty, 0)
LoadProperty(NameProperty, "")
LoadProperty(FirstNameProperty, "")
LoadProperty(LastNameProperty, "")
LoadProperty(FullNameProperty, "")
LoadProperty(EntityNameProperty, "")
LoadProperty(EntityNameProperty, "")
LoadProperty(LoginTypeProperty, "")
LoadProperty(ResultMessageProperty, "No data returned for " & criteria.UserName)
mRoles.Clear()

End If
End Using
End Using
End Using
Catch ex As Exception
LoadProperty(IsAuthenticatedProperty, False)
LoadProperty(CSLAUserKeyProperty, 0)
LoadProperty(NameProperty, "")
LoadProperty(FirstNameProperty, "")
LoadProperty(LastNameProperty, "")
LoadProperty(FullNameProperty, "")
LoadProperty(EntityNameProperty, "")
LoadProperty(EntityNameProperty, "")
LoadProperty(LoginTypeProperty, "")
LoadProperty(ResultMessageProperty, "Exception Occured for " & criteria.UserName & vbCrLf & ex.ToString)
mRoles.Clear()
End Try

End Sub

#End Region

End Class

End Namespace



Partial Class - used in SL client:

Imports System
Imports System.Security.Principal
Imports System.Collections.Generic
Imports System.Runtime.Serialization
Imports Csla
Imports Csla.Core
Imports Csla.Data
Imports Csla.Security
Imports Csla.Serialization
Imports Csla.Core.FieldManager
Imports Csla.DataPortalClient

Namespace Security

Partial Public Class desIdentity
Inherits ReadOnlyBase(Of desIdentity)
Implements IIdentity

#Region " Business Methods "

Protected Overrides Function GetIdValue() As Object
Return GetProperty(NameProperty)
End Function


#Region " IIdentity "


Private Shared ClientKeyProperty As PropertyInfo(Of Integer) = RegisterProperty(New PropertyInfo(Of Integer)("ClientKey"))

Private Shared IsAuthenticatedProperty As PropertyInfo(Of Boolean) = RegisterProperty(New PropertyInfo(Of Boolean)("IsAuthenticated"))
Private Shared AuthenticationTypeProperty As PropertyInfo(Of String) = RegisterProperty(New PropertyInfo(Of String)("AuthenticationType"))
Private Shared CSLAUserKeyProperty As PropertyInfo(Of Integer) = RegisterProperty(New PropertyInfo(Of Integer)("CSLAUserKey"))
Private Shared NameProperty As PropertyInfo(Of String) = RegisterProperty(New PropertyInfo(Of String)("Name"))
Private Shared FirstNameProperty As PropertyInfo(Of String) = RegisterProperty(New PropertyInfo(Of String)("FirstName"))
Private Shared LastNameProperty As PropertyInfo(Of String) = RegisterProperty(New PropertyInfo(Of String)("LastName"))
Private Shared FullNameProperty As PropertyInfo(Of String) = RegisterProperty(New PropertyInfo(Of String)("FullName"))
Private Shared EntityNameProperty As PropertyInfo(Of String) = RegisterProperty(New PropertyInfo(Of String)("EntityName"))
Private Shared EntityKeyProperty As PropertyInfo(Of Integer) = RegisterProperty(New PropertyInfo(Of Integer)("EntityKey"))
Private Shared LoginTypeProperty As PropertyInfo(Of String) = RegisterProperty(New PropertyInfo(Of String)("LoginType"))
Private Shared ResultMessageProperty As PropertyInfo(Of String) = RegisterProperty(New PropertyInfo(Of String)("ResultMessage"))

Public ReadOnly Property AuthenticationType() As String _
Implements System.Security.Principal.IIdentity.AuthenticationType
Get
Return "Csla"
End Get
End Property

Public ReadOnly Property IsAuthenticated() As Boolean _
Implements System.Security.Principal.IIdentity.IsAuthenticated
Get
Return GetProperty(IsAuthenticatedProperty)
End Get
End Property

Public ReadOnly Property CSLAUserKey() As Integer 'Added 3/20/2008 - gpd
Get
Return GetProperty(CSLAUserKeyProperty)
End Get
End Property

Public ReadOnly Property Name() As String _
Implements System.Security.Principal.IIdentity.Name
Get
Return GetProperty(NameProperty)
End Get
End Property

Public ReadOnly Property FirstName() As String
Get
Return GetProperty(FirstNameProperty)
End Get
End Property


Public ReadOnly Property LastName() As String
Get
Return GetProperty(LastNameProperty)
End Get
End Property

Public ReadOnly Property FullName() As String
Get
Return GetProperty(FullNameProperty)
End Get
End Property

Public ReadOnly Property EntityName() As String
Get
Return GetProperty(EntityNameProperty)
End Get
End Property

Public ReadOnly Property EntityKey() As Integer
Get
Return GetProperty(EntityKeyProperty)
End Get
End Property

Public ReadOnly Property LoginType() As String
Get
Return GetProperty(LoginTypeProperty)
End Get
End Property

Public ReadOnly Property ResultMessage() As String
Get
Return GetProperty(ResultMessageProperty)
End Get
End Property

#End Region

#End Region

#Region "Asynchronous/Shared Factory Methods "

Public Sub New()
' require use of factory methods
'When used, set Authenticated to false by default
LoadProperty(IsAuthenticatedProperty, False)
LoadProperty(CSLAUserKeyProperty, 0)
LoadProperty(NameProperty, "")
LoadProperty(FirstNameProperty, "")
LoadProperty(LastNameProperty, "")
LoadProperty(FullNameProperty, "")
LoadProperty(EntityNameProperty, "")
LoadProperty(EntityNameProperty, "")
LoadProperty(LoginTypeProperty, "")
LoadProperty(ResultMessageProperty, "Created new unauthenticated identity")
End Sub

Private Shared Sub desIdentityFetchComplete(ByVal sender As Object, ByVal e As DataPortalResult(Of desIdentity))

Dim callback = DirectCast(e.UserState, EventHandler(Of DataPortalResult(Of desIdentity)))

'Process results here - the object can now be manipulated before being passed back to the callback
'Callback to the UI that the identity has been established
callback.Invoke(sender, e)
End Sub

Public Shared Sub GetIdentityAsynch(ByVal entityid As String, ByVal username As String, ByVal password As String, ByVal callback As EventHandler(Of DataPortalResult(Of desIdentity)))
'Asynchronous Get method.
Dim dp = New DataPortal(Of desIdentity)
AddHandler dp.FetchCompleted, AddressOf desIdentityFetchComplete
dp.BeginFetch(New LoginCriteria(entityid, username, password), callback)
End Sub


Friend Shared Function UnauthenticatedIdentity() As desIdentity
Return New desIdentity
End Function


#End Region

End Class

End Namespace

RockfordLhotka replied on Monday, October 19, 2009

In reality the Silverlight data portal isn't what calls your DataPortal_Fetch() method. It is the .NET data portal that calls that method.

The SL data portal simply transfers the call to the .NET application server, and then delegates the call into the .NET data portal.

This means that the server-side code is pure .NET - and is actually exactly the same as if Silverlight wasn't involved at all.

So one thing you should probably do is create a unit test on .NET that calls DataPortal.Fetch() to make sure the code works on .NET at all.

If your .NET code does work as expected, then the next step is to make sure that the SL data portal is configured to talk to your app server - and you could walk through the BeginFetch() call in the debugger to make sure it gets into WcfProxy as expected.

GregDobbs replied on Monday, October 19, 2009

Thanks much for your reply Rocky.

The code works great on .Net as I am able to successfully use server-side code in a WPF application.

So, the problem is then how do I configure the SL data portal to communicate with the app server? I thought that this was simply setting up the service references in CSLALight and having the appropriate ServiceReferences.ClientConfig file in the Silverlight application.

I have all this set up properly - Ctrl-clicking the service reference URL in code brings me to the web page description of the service as it should.

Yet, I still receive the DataPortal_fetch not implemented exception.

I will try to step through the code to see if I can find anything. I am just wondering if there is some code I am missing that's required other than just the service references, Web.Config and ClientConfig files that is needed to to communicate with the WcfProxy?

RockfordLhotka replied on Monday, October 19, 2009

Have you watched the n-tier video in the CSLA .NET for Silverlight video series? In that video I walk through all the ways to configure the Silverlight data portal (there are several).

You need to set up an endpoint on your app server for the Silverlight data portal (it isn't compatible with the .NET data portal). That's all CSLA .NET for Windows stuff, and requires a svc file and web.config entries.

Then you need to set up the clientconfig file on the client side to point to the URL of the server endpoint.

It sounds like you've done this?

In that case my guess is that your call is flowing across, but isn't finding the correct overload of DataPortal_Fetch().

Remember that the data portal uses normal overloading rules. So the parameter type you pass to BeginFetch() on the client must be the parameter type accepted by your DataPortal_Fetch() method. Often this is a SingleCriteria object, but you can use custom criteria types as well.

The exception you are getting is occurring because the data portal is falling back to calling the default DP_Fetch() implementation, which throws a NotImplementedException.

GregDobbs replied on Tuesday, October 20, 2009

Thank you, Rocky.

The video did indeed have the solution. Sometimes things are so obvious only after the fact:

I needed to comment out the line:

Csla.DataPortal.ProxyTypeName = "Local"

in the Application_Startup method of the SL application. Problem solved!


Private Sub Application_Startup(ByVal o As Object, ByVal e As StartupEventArgs) Handles Me.Startup
'MAKE SURE to comment out or delete the following line to use a remote dataportal!!!!!!!!!!!!!!!!!
'This caused all the DataPortal_fetch not implemented errors I was getting.
'Csla.DataPortal.ProxyTypeName = "Local"
Me.RootVisual = New Main
End Sub

Copyright (c) Marimer LLC