WcfPortal.Fetch failes with FileNotFoundException

WcfPortal.Fetch failes with FileNotFoundException

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


marcelvb posted on Monday, November 14, 2011

Hi all,

I created a Silverlight 4 app with CSLA business objects on the server side. Unfortunately I cannot get it to work. When I try to retrieve a business object Project using its ID (integer) it seems like the fetch fails somewhere between the server receiving the request and calling my fetch method. After some debugging I found the following exception in the Error property of my viewmodel:

{System.IO.FileNotFoundException: Could not load file or assembly 'Atlas.WorkService.ManagementApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, Boolean loadTypeFromPartialName, ObjectHandleOnStack type)
   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName)
   at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
   at System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
   at Csla.Reflection.MethodCaller.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
   at Csla.Reflection.MethodCaller.GetType(String typeName)
   at Csla.Serialization.Mobile.MobileFormatter.GetTypeFromCache(String typeName)
   at Csla.Serialization.Mobile.MobileFormatter.DeserializeAsDTO(List`1 deserialized)
   at Csla.Serialization.Mobile.MobileFormatter.Deserialize(List`1 data)
   at Csla.Serialization.Mobile.MobileFormatter.Deserialize(XmlReader reader)
   at Csla.Serialization.Mobile.MobileFormatter.Deserialize(Stream serializationStream)
   at Csla.Serialization.Mobile.MobileFormatter.Deserialize(Byte[] data)
   at Csla.Server.Hosts.Silverlight.WcfPortal.GetCriteria(Byte[] criteriaData)
   at Csla.Server.Hosts.Silverlight.WcfPortal.Fetch(CriteriaRequest request)
}

ManagementApp is my Silverlight application. It does not make sense that the server side needs a reference to my Silverlight application. Any ideas? I have been going over my code for 2 days now and I can't find what I'm doing wrong here.

Regards,

Marcel

RockfordLhotka replied on Monday, November 14, 2011

The stack trace indicates that this is occuring while the message from the client is being deserialized on the server.

Based on this, it looks like one of your business objects must have a property or field that references some object or type in the Atlas.WorkService.ManagementApp assembly, and that is causing the deserialization process to attempt to load that type.

If you can't find this reference in your code, you can use something like fiddler to look at the XML being sent over the network - that might help you figure out which of your objects/properties/fields has this reference.

marcelvb replied on Tuesday, November 15, 2011

Hi Rocky,

 

Thanks for answering. I came to the same conclusion when studying the stacktrace. But the interesting thing is that the business objects that are used in the Silverlight assembly (Atlas.WorkService.ManagementApp) are links to the business objects in the server part (Atlas.WorkService.BusinessLogic). So I guess it's impossible for those to reference something in the Silverlight assembly.

What I do notice when debugging, is that the callback parameter contains a reference to has a Target property that references Atlas.WorkService.ManagementApp.ViewModels.ProjectUoWViewModel. So maybe I call my business object the wrong way?

Some extra info: I'm using the CompressedHost mechanism. I tried it with compression enabled and disabled. If I use Fiddler, would I see anything human-readable?

Let me show you some relevant code:

-----------------------

HomeViewModel.cs:

using System;
using System.Windows;
using Bxf;
using Csla.Xaml;
using Atlas.WorkService.ManagementApp.Views;
 
namespace Atlas.WorkService.ManagementApp.ViewModels
{
  public class HomeViewModel : DependencyObject
  {
    public void OpenProject(object sender, ExecuteEventArgs e)
    {
      var projectId = 0;
      if (e.MethodParameter != null && Int32.TryParse(e.MethodParameter.ToString(), out projectId))
      {
        Shell.Instance.ShowView(typeof(ProjectView).AssemblyQualifiedName, "projectViewModel", 
new ProjectUoWViewModel(projectId), "Content");       }     }   } }
-----------------------

ProjectViewModel.cs:

using System.Windows;
using Atlas.WorkService.BusinessLogic;
using Bxf;
using Csla.Xaml;

namespace Atlas.WorkService.ManagementApp.ViewModels { public sealed class ProjectUoWViewModel : ViewModel<ProjectUoW> { public ProjectUoWViewModel() { BeginRefresh("NewProject"); } public ProjectUoWViewModel(int projectId) { ManageObjectLifetime = true; Shell.Instance.ShowStatus(new Status { Text = "Getting project", IsBusy = true }); BeginRefresh("GetProject", projectId); } public static readonly DependencyProperty ProjectViewModelProperty = DependencyProperty.Register("ProjectViewModel"typeof(ProjectViewModel), typeof(ProjectUoWViewModel), null); public ProjectViewModel ProjectViewModel { get { return (ProjectViewModel)GetValue(ProjectViewModelProperty); } set { SetValue(ProjectViewModelProperty, value); } } protected override void OnRefreshed() { base.OnRefreshed(); // Set the Project in the ProjectViewModel ProjectViewModel = new ProjectViewModel(Model.Project); Shell.Instance.ShowStatus(new Status()); } } public class ProjectViewModel : ViewModel<Project> { #region Constructor public ProjectViewModel(Project project) { ManageObjectLifetime = false; Model = project; } #endregion Constructor protected override void BeginSave() { Shell.Instance.ShowStatus(new Status { IsBusy = true, Text = "Saving changes" }); base.BeginSave(); } protected override void OnSaved() { Shell.Instance.ShowStatus(new Status()); base.OnSaved(); } } }

-----------------------
ProjectUoW.cs (shared using a link between server and client):

using System; using Csla; #if SILVERLIGHT using Csla.Serialization; #endif namespace Atlas.WorkService.BusinessLogic {   [Serializable]   public partial class ProjectUoW : ReadOnlyBase<ProjectUoW>   {     #region Business Methods     public static PropertyInfo<Project> ProjectProperty = RegisterProperty<Project>(c => c.Project);     public Project Project     {       get { return GetProperty(ProjectProperty); }     }     #endregion     #region Factory Methods     public static void GetProject(int projectId, EventHandler<DataPortalResult<ProjectUoW>> callback)     {       var dp = new DataPortal<ProjectUoW>();       dp.FetchCompleted += callback;       dp.BeginFetch(new SingleCriteria<ProjectUoWint>(projectId));     }     #endregion Factory Methods   } }

-----------------------
ProjectUoW.server.cs:

using Csla; namespace Atlas.WorkService.BusinessLogic {   public partial class ProjectUoW   {     public void DataPortal_Fetch(SingleCriteria<ProjectUoWint> projectId)     {       LoadProperty(ProjectProperty, Project.NewProject());    }   } }

-----------------------
Project.cs (shared using a link between server and client):

using System; using System.Xml.Linq; using Atlas.WorkService.Common; using Csla; #if SILVERLIGHT using Csla.Serialization; #endif namespace Atlas.WorkService.BusinessLogic {   [Serializable]   public partial class Project : BusinessBase<Project>   {     #region Business Properties     private static readonly PropertyInfo<int> idProperty = RegisterProperty(new PropertyInfo<int>("Id""Id"));     public int Id     {       get { return GetProperty(idProperty); }       set { SetProperty(idProperty, value); }     }
    // Left out other properties here for brevity...
    #endregion     #region Factory Methods     public static void NewProject(EventHandler<DataPortalResult<Project>> callback)     {       var dp = new DataPortal<Project>();       dp.CreateCompleted += callback;       dp.BeginCreate();     }     public static void GetProject(int projectId, EventHandler<DataPortalResult<Project>> callback)     {       var dp = new DataPortal<Project>();       dp.FetchCompleted += callback;       dp.BeginFetch(new SingleCriteria<Projectint>(projectId));     }     #endregion Factory Methods   } }
-----------------------
Project.server.cs:

using System; using System.Collections.Generic; using System.Runtime.Caching; using System.Xml.Linq; using Atlas.WorkService.Common; using Atlas.WorkService.DataAccess.Repositories; using Csla; using ProjectUser = Atlas.WorkService.DataAccess.Mapping.ProjectUser; namespace Atlas.WorkService.BusinessLogic {   public partial class Project   {     private static readonly MemoryCache projectCache = new MemoryCache("Project");     private Project()     {     }     public static Project GetProject(int id)     {       return DataPortal.Fetch<Project>(new SingleCriteria<Projectint>(id));     }     public static Project NewProject()     {       return DataPortal.Create<Project>();     }     public static void DeleteProject(int id)     {       DataPortal.Delete<Project>(new SingleCriteria<Projectint>(id));     }     public static bool Exists(int id)     {       return ExistCommand.Execute(id);     }     private DataAccess.Mapping.Project AsDto()     {       DataAccess.Mapping.Project projectDto = new DataAccess.Mapping.Project                                                 {                                                   Id = Id,
// Left out other properties here...
                                                 };       return projectDto;     }     public override void Delete()     {       ProjectRepository.Instance.Delete(AsDto());     }     public IDictionary<UserICollection<JobUserRole>> GetProjectUsers()     { // Left out implementation here....     }     protected override void DataPortal_Insert()     {       DataAccess.Mapping.Project projectDto = ProjectRepository.Instance.Add(AsDto());       Id = projectDto.Id;     }     protected override void DataPortal_Update()     {       ProjectRepository.Instance.Update(AsDto());     }     protected override void DataPortal_DeleteSelf()     {       ProjectRepository.Instance.Delete(AsDto());     }     public void DataPortal_Fetch(SingleCriteria<Projectint> criteria)     {       int projectId = criteria.Value;       DataAccess.Mapping.Project project;       if (projectCache.Contains(projectId.ToString()))       {         project = (DataAccess.Mapping.Project)projectCache.Get(projectId.ToString());       }       else       {         project = ProjectRepository.Instance.GetByKey(projectId);         projectCache.Add(projectId.ToString(), project, new CacheItemPolicy());       }       if (project == nullreturn;       Id = project.Id;       Description = project.Description;       Status = project.Status;       ProjectType = MetadataType.GetMetadataType(project.ProjectTypeId);       WorkItemType = MetadataType.GetMetadataType(project.WorkItemTypeId);       Metadata = project.Metadata == null ? null : XDocument.Parse(project.Metadata);     }     #region ExistsCommand     [Serializable]     private class ExistCommand : CommandBase<ExistCommand>     {
// Left out implementation here....
    }     #endregion ExistsCommand     public override bool Equals(object obj)     {       if (obj != null && obj.GetType() == this.GetType())         return Id == ((Project)obj).Id;       return false;     }     public override int GetHashCode()     {       return Id;     }   } }

RockfordLhotka replied on Tuesday, November 15, 2011

Just to confirm, you are using the project/assembly structure shown in the Using CSLA 4 ebook series and the CSLA 4 MVVM video series right?

That is to say you have projects like this:

  1. UI project (views, viewmodels)
  2. Business project (business classes, compiled for SL)
  3. Business project (business classes, compiled for .NET)
  4. DAL project (data access types)

Projects 2 and 3 are the exact same project, except they compile to SL and .NET respectively. Project 2 is deployed to the client. Project 3 is deployed to the server.

marcelvb replied on Tuesday, November 15, 2011

Yes, that is basically it, except that I put the Silverlight business objects in the same project as UI project. As I understand it, it is both compiled to SL and put in the same XAP package anyway. Is this a shortcut that is biting my in the butt? I get the feeling my problem is some sort of DLL hell.

Another problem that I just had, that is different but feels like it is related, is that my unit test that test the business objects failed on the TFS-server. At runtime it said it failed to open System.Windows.dll (SL version!!). It seems like the web project that hosts the CSLA/WCF service and also contains the test page and SL XAP, caused the server version of Csla.dll to end up in the same directory as the SL version of Csla.dll. I solved it by excluding the SL and Web projects on the TFS-server.

RockfordLhotka replied on Tuesday, November 15, 2011

Yes, that is your problem.

The data portal (really it is serialization) requires that the client and server assemblies containing your business types "be the same".

What that really means is that they must have the same strongly qualified assembly name, and that each type in the assembly has the same full type name (namespace, class, assembly name).

marcelvb replied on Tuesday, November 15, 2011

That did the trick! Smile

Thanks a lot for your swift response.

 

Regards,

Marcel

Copyright (c) Marimer LLC