powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WCF, Web Services, Remoting [игнор отключен] [закрыт для гостей] / WCF+NHibernate
7 сообщений из 7, страница 1 из 1
WCF+NHibernate
    #37332826
Balda_1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть WCF сервис, в котором доступ к БД реализован с помощью NHibernate.
Сервис возвращает список сотрудников. Каждый сотрудник имеет номер, имя, фамилию, дату рождения и семейное положение (тянется из словаря).
Код службы:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
[ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class NHEmployeeService
    {
        [OperationContract]
        public IList<PersonalInfo> GetAllEmployees()
        {
            return Global.CurrentSession.CreateCriteria(typeof(PersonalInfo)).List<PersonalInfo>();
        }
    }
Вызов службы на клиенте:
Код: plaintext
1.
2.
3.
var proxy = new NHServiceReference.NHEmployeeServiceClient();
            proxy.GetAllEmployeesCompleted += new System.EventHandler<NHServiceReference.GetAllEmployeesCompletedEventArgs>(proxy_GetAllEmployeesCompleted);
            proxy.GetAllEmployeesAsync();

Классы NHibernate объектов:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
    [DataContract]
    public class PersonalInfo
    {
        [DataMember]
        public virtual int EmployeeID { get; protected set; }
        [DataMember]
        public virtual string FirstName { get; set; }
        [DataMember]
        public virtual string LastName { get; set; }
        [DataMember]
        public virtual DateTime BirthDate { get; set; }
        [DataMember]
        public virtual FamilyStatus FamilyStatus { get; set; }
    }

    [DataContract]
    public class FamilyStatus
    {
        [DataMember]
        public virtual int StatusID { get; set; }
        [DataMember]
        public virtual string StatusName { get; set; }
        [DataMember]
        public virtual IList<PersonalInfo> Employees { get; set; }
    }

Мапинги:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
public class PersonalInfoMap : ClassMap<PersonalInfo>
    {
        public PersonalInfoMap()
        {
            Table("PersonalInfo");
            Id(x => x.EmployeeID).GeneratedBy.Identity();
            Map(x => x.FirstName).Column("FirstName");
            Map(x => x.LastName).Column("LastName");
            Map(x => x.BirthDate).Column("BirthDate");
            References(x => x.FamilyStatus, "FamilyStatus");
        }
    }

    public class FamilyStatusMap : ClassMap<FamilyStatus>
    {
        public FamilyStatusMap()
        {
            Table("FamilyStatus");
            Id(x => x.StatusID).GeneratedBy.Identity();
            Map(x => x.StatusName).Column("StatusName");
            HasMany(x => x.Employees).AsList().Inverse().Cascade.None();
        }
    }

При выполнеии вылетает сообщение об ошибке:
"Type 'Castle.Proxies.FamilyStatusProxy' with data contract name 'FamilyStatusProxy:http://schemas.datacontract.org/2004/07/Castle.Proxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer."

Добавление атрибута KnownTypeAttribute не помогло:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
[KnownTypeAttribute(typeof(FamilyStatus))]
    [DataContract]
    public class PersonalInfo
    {
        [DataMember]
        public virtual int EmployeeID { get; protected set; }
        [DataMember]
        public virtual string FirstName { get; set; }
        [DataMember]
        public virtual string LastName { get; set; }
        [DataMember]
        public virtual DateTime BirthDate { get; set; }
        [DataMember]
        public virtual FamilyStatus FamilyStatus { get; set; }
    }

Подскажите, пожалуйста, как исправить ошибку?
...
Рейтинг: 0 / 0
WCF+NHibernate
    #37334173
МихаилР
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Balda_1,

Судя по всему, Вы нарвались на типичную проблему работы связки WCF + NHibernate. У вас используется Lazy Loading, а значит связанные данные вытягиваются не в виде объявленногов вами класса (FamilyStatus - кстати, объявлять его как KnownType нет никакого смысла - этот тип и так явно используется в объявлении типа PersonalInfo), а в виде автоматически сгенерированного Castle.Proxies.FamilyStatusProxy, о котором WCF ничего не знает.

Что можно сделать? Если я еще окончательно не забюыл NH, то возможны следующие варианты:
не использовать lazy loading - все объяекты будут загружаться явно. Но в случае сложного графа (с большим количеством связей) вы получите страшную картину

отказаться от передачи связанных свойств - загружать связанные колекции явно (именно к такому варианту подталкивает WCF Data Service, хотя и там есть expand)

использовать суррогаты данных. Там суть в том, что прежде чем произвести сериализацию данных, WCF будет вызывать ваш код для инспекции графа объектов, причем этот инспектор может на ходу заменять части графа. В вашем варианте это будет означать, что вы можете вместо proxy явно достать нужный объект из базы (или коллекцию) и вернуть сериализатору уже реальные объекты.
В качестве примера посмотрите вот эту статью WCF serialization with NHibernate object graphs . Особенно внимательно прочитайте комментарии - статья писалась для NH 2.0, если не ошибаюсь, а в 3.0 многое менялость (особенно в свете того, что у них тепереь используется заменяемый движок для proxy).

Ну и самый радикальный способ - перейти на использование EF, для которого отдельно делалась поддержка WCF, но там будет куча своих проблем.
...
Рейтинг: 0 / 0
WCF+NHibernate
    #37335342
Balda_1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Пробую реализовать суррогаты данных:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
public class HibernateDataContractSurrogate : IDataContractSurrogate
    {
        #region IDataContractSurrogate Members

        public object GetObjectToSerialize(object obj, Type targetType)
        {
            INHibernateProxy proxy = obj as INHibernateProxy;
            if (proxy != null)
            {
                ILazyInitializer li = proxy.HibernateLazyInitializer;
                obj = (li.IsUninitialized ? null : li.GetImplementation());
            }

            return obj;
        }

        public object GetCustomDataToExport(Type clrType, Type dataContractType)
        {
            return null;
        }

        public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
        {
            return null;
        }

        public Type GetDataContractType(Type type)
        {
            return type;
        }

        public object GetDeserializedObject(object obj, Type targetType)
        {
            return obj;
        }

        public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
        {

        }

        public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
        {
            return null;
        }

        public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
        {
            return typeDeclaration;
        }

        #endregion
    }
В результате при вызове службы вылетает ошибка: "Unable to cast object of type 'System.Object' to type 'TestEmployees.NHServiceReference.FamilyStatus'."

Откуда взялось несоответствие типов и как это поправить?
...
Рейтинг: 0 / 0
WCF+NHibernate
    #37335710
МихаилР
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Balda_1Откуда взялось несоответствие типов и как это поправить?
Я давно не работал с сурогатами, но подозреваю, что WCF не нравится тип, который вы ему возвращаете в GetDataContractType. Посмотрите под отладкой - что там происходит
...
Рейтинг: 0 / 0
WCF+NHibernate
    #37335796
Balda_1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Там просто возвращается полученный тип данных:
Код: plaintext
1.
2.
3.
4.
public Type GetDataContractType(Type type)
        {
            return type;
        }
В отладке на вход принимаем NHCore.FamilyStatus (NHCore - проект, в котором содержатся классы описания объектов) и его же возвращаем.
Может ошибка из-за того, что описания классов находятся в другом проекте, а не в проекте WCF?
...
Рейтинг: 0 / 0
WCF+NHibernate
    #37338473
МихаилР
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Balda_1Может ошибка из-за того, что описания классов находятся в другом проекте, а не в проекте WCF?
Врятли.
Он же их нормально находит.

К сожалению нет сейчас возможности воспроизвести ваш пример и посмотреть. А по памяти - уже не всплывает ничего. Попробуйте сделать следующее:
1. Посмотреть под отладкой как работает GetObjectToSerialize - не исключено, что не верно работает материализация объекта (кстати, еще такой момент - на сколько я помню для загрузки коллекций использовались какие-то отдельные методы. Это когда дойдет дело до загрузки Employees).
2. Включить трассирование на сервере и посмотреть где конкретно происходит падение - может это и не связано с сурогатом.
...
Рейтинг: 0 / 0
WCF+NHibernate
    #37338609
Balda_1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
МихаилР,

спасибо за помощь ))
Буду копать...
...
Рейтинг: 0 / 0
7 сообщений из 7, страница 1 из 1
Форумы / WCF, Web Services, Remoting [игнор отключен] [закрыт для гостей] / WCF+NHibernate
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]