开发者

Multiple interceptors in NHibernate

I am very new to NHibernate and have been following various tutorials online, especially this one to create my own program. I really liked the use of the interceptor to add INotifyPropertyChanged to entities created using the DataBindingFactory and tried to follow the same idea to add IDataErrorInfo to entities created by the DataBindingFactory with another method CreateWithValidation(Type type):

public static object CreateWithValidation(Type type)
{
    return _proxyGenerator.CreateClassProxy(type, new[]
    {
        typeof (IDataErrorInfo),
        typeof (INotifyPropertyChanged)
    }, new IInterceptor[]
    {
        new NotifyPropertyChangedInterceptor(type.FullName),
        new DataErrorInfoInterceptor()
    });
}

The code for the NotifyPropertyChangedInterceptor is the same as in the linked article and below is my implementation of the DataErrorInfoInterceptor class which came from this article:

public class DataErrorInfoInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        if (invocation.Method.DeclaringType.Equals(typeof(IDataErrorInfo)))
        {
            var validator = new ValidatorEngine();
            var errors = validator.Validate(invocation.Proxy);

            if (invocation.Method.Name.Equals("get_Item"))
            {
                String propertyName = Convert.ToString(invocation.Arguments[0]);
                var propertyErrors = errors
                                       .Where(e => e.PropertyName.Equals(propertyName))
                                       .Select(e => e.Message)
                                       .ToArray();

                if (propertyErrors.Count() > 0)
                {
                    invocation.ReturnValue = string.Join(Environment.NewLine, propertyErrors);
                }
                else
                {
                    invocation.ReturnValue = null;
                }
            }
            else if (invocation.Method.Name.Equals("get_Error"))
            {
                var allErrors = errors
                                  .Select(e => e.Message)
                                  .ToArray();

                if (allErrors.Count() > 0)
                {
                    invocation.ReturnValue = string.Join(Environment.NewLine, allErrors);
                }
                else
                {
                    invocation.ReturnValue = null;
                }
            }
            else
            {
                invocation.Proceed();
            }
        }
    }

The problem that I have is that if I create an object using the CreateWithValidation() method and use it on a model, any text I enter into a textbox on the view is cleared when I tab away from the field (this probably happens in other fields as well but I've only tried it on textboxes). I suspect that this is because both of the classes implementing IInterceptor have the line invocation.Proceed() if the method that has been intercepted is not one that the class is interested in.

My question is, is it possible to have two interceptors like this or do I have to have one massive class, eg: CustomInterceptor which has all of the methods for, eg: INotifyPropertyChanged and IDataErrorInfo and deal with them there? That seems quite unwieldy to me.

For what it's worth, this is how I set the interceptor on my SessionFactory:

public static void Initialise()
{
    Configuration config =  Fluently.Configure()
                                      .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c
                                        .Server("")
                                        .Database("")
                                        .Username("")
                                        .Password("")))
                                      .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Map>()
                                        .Conventions.AddFromAssemblyOf<EnumCon开发者_StackOverflow社区vention>())
                                      .BuildConfiguration();

    ConfigureNhibernateValidator(config);

    DataBindingInterceptor interceptor = new DataBindingInterceptor();
    SessionFactory = config
                       .SetInterceptor(interceptor)
                       .BuildSessionFactory();

}


The problem is not multiple interceptors. And the problem is not calling invocation.Proceed(). The problem is that you don't call invocation.Proceed() in your DataErrorInfoInterceptor when the method is not from IDataErrorInfo (it's correct in the linked article). Because of this, when you call some getter or setter, nothing happens.

Right now, you have something like this:

if (invocation.Method.DeclaringType.Equals(typeof(IDataErrorInfo)))
{
    if (invocation.Method.Name.Equals("get_Item"))
    {
        // some code
    }
    else if (invocation.Method.Name.Equals("get_Error"))
    {
        // more code
    }
    else
    {
        invocation.Proceed();
    }
}

What you should have is this:

if (invocation.Method.DeclaringType.Equals(typeof(IDataErrorInfo)))
{
    if (invocation.Method.Name.Equals("get_Item"))
    {
        // some code
    }
    else if (invocation.Method.Name.Equals("get_Error"))
    {
        // more code
    }
}
else
{
    invocation.Proceed();
}

Next time, try stepping through the code in debugger to see what's really going on.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜