Castle DynamicProxy:为 XML 序列化创建具有自定义属性的新属性 [英] Castle DynamicProxy: create a new property with a custom attribute for XML serialization

查看:64
本文介绍了Castle DynamicProxy:为 XML 序列化创建具有自定义属性的新属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些应该实现的 DTO 类的情况,例如:

I have a situation where I have some DTO classes that should be implemented like:

public class City
{
  public string Name { get; set; }
  public State State { get; set; }
}

public class State
{
  public string Name { get; set; }
}

问题是,这些实际上是 REST XML 资源的 DTO 类.City 资源可能包含内联的 State 资源,或者它可能只提供资源 ID(一个 URI).我正在通过 Repository 模式处理对 DTO 的访问,并希望它对客户端透明,无论 State 是否延迟加载(就像 NHibernate 如何处理它的实体类一样).

The problem is, these are actually DTO classes for REST XML resources. And the City resource may include the State resource inline, or it may simply provide the resource ID (a URI). I am handling access to the DTO via the Repository pattern and would like it to be transparent to clients whether State is lazy loaded or not (like how NHibernate does with it's entity classes).

所以我目前的计划是当 REST 存储库检测到类没有完全水合"(即并非所有内容都是内联的)时,使用 Castle DynamicProxy 来创建代理对象.代理对象将知道如何根据需要延迟加载属性.

So my current plan is to use Castle DynamicProxy to create a proxy object when the REST Repository detects that the class isn't fully "hydrated" (i.e. not everything is inline). The proxy object will know how to lazy load attributes as needed.

然而,要实际实现这一点,我唯一想到的是为所有关系提供支持属性,并将 Xml 属性放在这些属性上.所以策略看起来像这样:

To actually implement this, however, the only thing I've come up with is to have backing attributes for all relationships and put the Xml attributes on those. So the strategy looks like this:

[XmlType]
public class City
{
  [XmlElement]
  public string Name { get; set; }

  [ToOneRestRelationship(BackingPropertyName = "StateBacking")]
  public State State { get; set; }

  [XmlElement(Name = "state")]
  public ResourceBase StateBacking { get; set; }
}

[XmlType]
public class State
{
  [XmlElement]
  public string Name { get; set; }
}

然后 Repository 对象知道设置代理对象以从 StateBacking 属性获取对象并使用它(内联资源案例)或执行 REST 请求以延迟检索 来自后备属性中指定的 ID 的状态 对象(资源 URI 情况,即惰性).

Then the Repository object knows to set up the proxy object to either get the object from the StateBacking property and use that (inlined resource case) or do a REST request to lazily retrieve the State object (resource URI case, i.e. lazy) from the ID specified in the backing property.

问题

问题是,这个支持字段非常难看.我想要的是一种让 Castle 生成一个类的方法,该类将具有后备属性应用了 XmlElement 属性,我可以将其传递给 XmlSerializer代码>.那么我的 DTO 类可能看起来更像第一个示例,并且不必知道实际的序列化类具有支持属性.

The issue is, this backing field is pretty ugly. What I would like is a way to have Castle generate a class that would have the backing property with the XmlElement attribute applied that I could pass to the XmlSerializer. Then my DTO classes could look more like the first example and wouldn't have to be aware that the actual serialising class has a backing property.

Castle 或任何其他代理库是否可以实现类似的功能?

Is something like this possible with Castle or any other Proxy library?

推荐答案

在走完一条有趣且完全错误的道路后,我认为确实可以创建一个客户看不到的支持字段.由于代理通过从代理类继承来工作,因此派生类上的任何属性都不会在原始类的范围内看到.所以混合是要走的路:

After going an interesting and completely wrong way, i think it is indeed possible to create a backing field that won't be seen by clients. Since proxying works by inheriting from the proxied class, any property on the derived class won't be seen in the scope of the original class. So mixins are the way to go:

给定 Foo

public class Foo
{
    public virtual string  Name { get; set; }
    public virtual Bar bar { get; set; }
}

和酒吧

public class Bar
{
    public virtual string Name { get; set; }
}

我们可以声明一个接口,让我们检索支持字段和实现

We can declare an interface that will let us retrieve the backing field and an implementation

public interface IHasBarBackingField
{
    Bar RetrieveBar();
}

public class HasBarBackingField : IHasBarBackingField
{
    public HasBarBackingField()
    {
        // the constructor must contain ways to resolve the bar. Since
        // the class is built while proxying you should have all the data
        // available at this moment
    }

    public Bar RetrieveBar()
    {
        return new Bar(); // example, you could have a backing field somewhere in this class
    }
}

然后你只需要在代理时混合两个类:

Then you just have to mixin both classes when proxying:

var pg = new ProxyGenerator();

var hasBarBackingField = new HasBarBackingField();

var options = new ProxyGenerationOptions();
options.AddMixinInstance(hasBarBackingField);
var test = pg.CreateClassProxy<Foo>(options, new BarInterceptor());

并拦截您感兴趣的呼叫以返回支持栏

and intercept the call interesting you in order to return the backing Bar

public class BarInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        if (invocation.Method.Name == "get_bar")
        {
            var hasBarBackingField = invocation.InvocationTarget as IHasBarBackingField;
            invocation.ReturnValue = hasBarBackingField.RetrieveBar();
        }
        else
        {
            invocation.Proceed();
        }
    }
}

应构建 HasBarBackingField 类以返回直接对象或检索引用的 REST 对象.希望这有帮助

The HasBarBackingField class should be built to return either the direct object or retrieve the referenced REST object. Hope this helps

这篇关于Castle DynamicProxy:为 XML 序列化创建具有自定义属性的新属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆