2013-09-18 5 views
2

Когда я пытаюсь получить документ, содержащий список сущностей, типы которых находятся в динамически загружаемой DLL, я получаю исключение JSONSerialisation, в котором говорится, что он не может найти тип динамически загруженного DLL: Could not load assembly 'Sandbox_One'Raven DB JsonSerializationException Не удалось загрузить сборку

Я использую RavenDB (сборка 2681) для хранения объектов, созданных с помощью Roslyn, хотя я не думаю, что это проблема. Каждый из объектов наследует нединамический интерфейс IEntity. Сессия Raven создается с обеих сторон действия .NET MVC 4 (согласно Raven example), и я могу сохранить динамический объект в списке IEntity.

Когда я пытаюсь загрузить список сущностей из документа, я получаю ошибку сериализации. На данный момент у меня есть только один экземпляр (Blue Eyes) одного типа сущности (Customer).

Наблюдения

  • В базе данных, объект выглядит точно так же, как я бы ожидать:
 
{ 
    "Entities": [ 
    { 
     "$type": "Prometheus.Dynamic.Sandbox_One.Customer, Sandbox_One", 
     "Name": "Customer", 
     "Eye_colour": "Blue", 
     "Age": 9.0, 
     "Id": "b0937393-b1bf-4bcb-97d7-1aea7a96e881" 
    } 
    ] 
} 
  • В пункте Загрузка сущности, я проверяю AppDomain.CurrentDomain для и Prometheus.Dynamic.Sandbox_One с типом Customer.

  • Объект Realm имеет ссылку на динамически загружаемой Ассамблеи, и я в состоянии отразить типы из него, как так:

    var customer = Activator.CreateInstance(realm.Assembly.GetTypes().First());

  • Ассамблея загружается в действие MVC, после RavenDB сеанс был запущен. Будет ли это иметь значение? Я не думаю, что, как я ожидаю, сериализатор JSON.net будет выглядеть в AppDomain.


код и исключение

Полный трассировка стека исключений:

[JsonSerializationException: Could not load assembly 'Sandbox_One'.] 
    Raven.Imports.Newtonsoft.Json.Serialization.DefaultSerializationBinder.GetTypeFromTypeNameKey(TypeNameKey typeNameKey) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\DefaultSerializationBinder.cs:69 
    Raven.Imports.Newtonsoft.Json.Utilities.ThreadSafeStore`2.AddValue(TKey key) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Utilities\ThreadSafeStore.cs:62 
    Raven.Imports.Newtonsoft.Json.Serialization.DefaultSerializationBinder.BindToType(String assemblyName, String typeName) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\DefaultSerializationBinder.cs:119 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadSpecialProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:473 

[JsonSerializationException: Error resolving type specified in JSON 'Prometheus.Dynamic.Sandbox_One.Customer, Sandbox_One'. Path 'Entities[0].$type'.] 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadSpecialProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:526 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:344 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:238 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IWrappedCollection wrappedList, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:1132 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:572 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:240 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:692 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:1593 

[JsonSerializationException: Could not read value for property: Entities] 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:1602 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:368 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:238 
    Raven.Imports.Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:164 
    Raven.Imports.Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) in c:\Builds\RavenDB-Stable\Imports\Newtonsoft.Json\Src\Newtonsoft.Json\JsonSerializer.cs:565 
    Raven.Client.Document.InMemoryDocumentSessionOperations.ConvertToEntity(Type entityType, String id, RavenJObject documentFound, RavenJObject metadata) in c:\Builds\RavenDB-Stable\Raven.Client.Lightweight\Document\InMemoryDocumentSessionOperations.cs:457 
    Raven.Client.Document.InMemoryDocumentSessionOperations.TrackEntity(Type entityType, String key, RavenJObject document, RavenJObject metadata, Boolean noTracking) in c:\Builds\RavenDB-Stable\Raven.Client.Lightweight\Document\InMemoryDocumentSessionOperations.cs:404 
    Raven.Client.Document.InMemoryDocumentSessionOperations.TrackEntity(Type entityType, JsonDocument documentFound) in c:\Builds\RavenDB-Stable\Raven.Client.Lightweight\Document\InMemoryDocumentSessionOperations.cs:388 
    Raven.Client.Document.InMemoryDocumentSessionOperations.TrackEntity(JsonDocument documentFound) in c:\Builds\RavenDB-Stable\Raven.Client.Lightweight\Document\InMemoryDocumentSessionOperations.cs:343 
    Raven.Client.Document.SessionOperations.LoadOperation.Complete() in c:\Builds\RavenDB-Stable\Raven.Client.Lightweight\Document\SessionOperations\LoadOperation.cs:61 
    Raven.Client.Document.DocumentSession.Load(String id) in c:\Builds\RavenDB-Stable\Raven.Client.Lightweight\Document\DocumentSession.cs:230 
    Prometheus.Core.DomainServices.DataManager.GetDataForRealm(IDocumentSession session, Realm realm) in c:\TeamProjectsCloud\Prometheus\Prometheus.Core\DomainServices\DataManager.cs:48 
    Prometheus.Portal.Controllers.DataController.Index(String entityName) in c:\TeamProjectsCloud\Prometheus\Prometheus.Portal\Controllers\DataController.cs:23 
    lambda_method(Closure , ControllerBase , Object[]) +192 
    System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +274 
    System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39 
    System.Web.Mvc.Async.c__DisplayClass39.b__33() +120 
    System.Web.Mvc.Async.c__DisplayClass4f.b__49() +452 
    System.Web.Mvc.Async.c__DisplayClass37.b__36(IAsyncResult asyncResult) +15 
    System.Web.Mvc.Async.c__DisplayClass2a.b__20() +33 
    System.Web.Mvc.Async.c__DisplayClass25.b__22(IAsyncResult asyncResult) +240 
    System.Web.Mvc.c__DisplayClass1d.b__18(IAsyncResult asyncResult) +28 
    System.Web.Mvc.Async.c__DisplayClass4.b__3(IAsyncResult ar) +15 
    System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53 
    System.Web.Mvc.Async.c__DisplayClass4.b__3(IAsyncResult ar) +15 
    System.Web.Mvc.c__DisplayClass8.b__3(IAsyncResult asyncResult) +42 
    System.Web.Mvc.Async.c__DisplayClass4.b__3(IAsyncResult ar) +15 
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288

Контроллер (я полужирным вызов, где грузятся Entities): NB RavenSession наследуется от базового контроллера точно так же, как в MVC site example

public ActionResult Index(string entityName) 
{ 
    var viewModel = new DataViewModel(); 
    var realm = realmManager.GetRealm(RavenSession, viewModel.SelectedRealm); 
    viewModel.Entities = realmManager.GetEntities(realm); 
    viewModel.CurrentEntity = viewModel.Entities.SingleOrDefault(x => x.Name == entityName); 
    viewModel.Data = dataManager.GetDataForRealm(RavenSession, realm); // Call to loading method 

    return View(viewModel); 
} 

Вызов нагрузки, который бросает исключение:

public List<IEntity> GetDataForRealm(IDocumentSession session, Realm realm) 
    { 
     var realmData = session.Load<RealmData>(realm.RealmDataId); // Exception thrown 
     return realmData.Entities; 
    } 

Царство класса данных:

public class RealmData 
{ 
    public RealmData() 
    { 
     Entities = new List<IEntity>(); 
    } 
    public List<IEntity> Entities { get; set; } 
} 

Заранее спасибо за вашу помощь!

ответ

2

Моим решением было реализовать обработчик событий AssemblyResolve в домене приложений.

Метод GetDataForRealm становится:

public List<IEntity> GetDataForRealm(IDocumentSession session, Realm realm) 
    { 
     AppDomain.CurrentDomain.AssemblyResolve += (s, a) => MyResolveEventHandler(s, a, realm.Assembly); 

     var realmData = session.Load<RealmData>(realm.RealmDataId); 
     return realmData.Entities; 
    } 

обработчик событий выглядит следующим образом:

private Assembly MyResolveEventHandler(object sender, ResolveEventArgs args, Assembly assembly) 
    { 
     if (assembly.GetName().Name == args.Name) 
     { 
      return assembly; 
     } 
     return null; 
    } 

То, что я считаю, что происходит:

Когда десериализатор JSON.Net отражал из динамического типа он не смог найти сборку в AppDomain.CurrentDomain. Обработчик вызывается, когда AppDomain не может найти сборку по имени. Моя сборка была в AppDomain (поскольку я использовал Assembly.Load), но ее не удалось найти.

Примечание: Я продлил MyResolveEventHandler с дополнительным параметром, так как я уже имел ассамблею я нуждался. Если у вас нет сборки в памяти (но знаете, где она), вы можете загрузить ее внутри MyResovleEventHandler.

Update

Вы можете обнаружить, что у вас есть проблемы, назначая данные этих результирующих объектов позже. Это связано с тем, что передача объекта через AppDomain не означает, что он изменяет домен объекта. Вместо этого он просто передает ссылку. Вместо этого я обнаружил, что было проще получить RavenDB для создания объектов в правильном (временном) домене в первую очередь с помощью настраиваемого конвертера JSON, который имеет динамическую сборку в члене. See that solution here.

Смежные вопросы