Can I define custom attributes for proxy type in Castle Windsor
Asked Answered
R

2

8

I have a class that I proxy it with Castle Dynamic Proxy. I want to add some custom Attributes to proxy methods (which is not defined in proxied class). Is this possible.

I want this because I want to generate ASP.NET Web API layer for my application's Service Layer. I proxied services (with inheriting from ApiController and additional IMyService interfaces), it works great but I want to add WebAPI specific attributes to this newly created Dynamic class, thus Web API framework can read them.

EDIT:

I want to explain detailed if someone want to know what I want actually.

public interface IMyService
{
    IEnumerable<MyEntity> GetAll();
}

public class MyServiceImpl : IMyService
{
    public IEnumerable<MyEntity> GetAll()
    {
        return new List<MyEntity>(); //TODO: Get from database!
    }
}

public class MyServiceApiController : ApiController,IMyService
{
    private readonly IMyService _myService;

    public MyServiceApiController(IMyService myService)
    {
        _myService = myService;
    }

    public IEnumerable<MyEntity> GetAll()
    {
        return _myService.GetAll();
    }
}

Think that I have a IMyService which is implemented by MyServiceImpl. And I want to make a Api controller to be able to use this service from web. But as you see, api controller is just a proxy for real service. So, why I should write it? I can dynamically create it using castle windsor.

This is my idea and almost done it in my new project (https://github.com/hikalkan/aspnetboilerplate). But what if I need to add some attribute (such as Authorize) to GetAll method of the api controller. I cant directly add since there is no such a class, it's castle dynamic proxy.

So, beside this problem. I want to know if it's possible to add a attribute to a method of a synamic proxy class.

Redan answered 11/9, 2013 at 7:36 Comment(5)
Does Web API really read those attributes? What I'm used to with MVC is that only the Controller base class reads the attributes on its derived classes, so you can safely wrap such class, since MVC only interacts with IController. Doesn't this work the same for Web API? Thus ApiController reads attributes while Web API only interacts with IHttpController? Otherwise the IHttpController abstraction would be broken.Intemperate
WebAPI has some attributes, such as Authorize, FromBody and FromUri attributes (see asp.net/web-api/overview/formats-and-model-binding/…). Also, I can not define such attributes in my service layer since it's independed from web api layer. So, when I create a dynamic web api, I have to inject these attributes the newly created web api class.Redan
Also, I may want to add custom attributes to proxy class, methods (even to parameters of a method) beyond this case.Redan
If I'm not mistaken, you can wrap any decorator around an ApiController and those attributes will still be applied (since the ApiController reflects over itself, not the decorator) and any attributes that you declare on the proxy will never be processed, since Web API itself does not reflect the called IHttpController, but only the ApiController does this. I advice you to check this out by writing a small manual decorator and wrap your controllers by implementing a custom controller activator.Intemperate
I edited the question to explain detailed.Redan
E
2

See again that project https://github.com/aspnetboilerplate/aspnetboilerplate/issues/55 I also want to know how, so that I can define RoutePrefix on IService and Route on Action. Fortunately, I finally know how to define custom attributes for proxy.

public class CustomProxyFactory : DefaultProxyFactory
{
    #region Overrides of DefaultProxyFactory

    protected override void CustomizeOptions(ProxyGenerationOptions options, IKernel kernel, ComponentModel model, object[] arguments)
    {
        var attributeBuilder = new CustomAttributeBuilder(typeof(DescriptionAttribute).GetConstructor(new[] { typeof(string) }), new object[] { "CustomizeOptions" });
        options.AdditionalAttributes.Add(attributeBuilder);
    }

    #endregion
}

/// <summary>
/// 用户信息服务
/// </summary>
[Description("IUserInfoService")]
public interface IUserInfoService
{
    /// <summary>
    /// 获取用户信息
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    [Description("IUserInfoService.GetUserInfo")]
    UserInfo GetUserInfo([Description("IUserInfoService.GetUserInfo name")] string name);
}

/// <summary>
/// 用户信息服务
/// </summary>
[Description("UserInfoService")]
public class UserInfoService : IUserInfoService
{
    /// <summary>
    /// 获取用户信息
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    [Description("UserInfoService.GetUserInfo")]
    public virtual UserInfo GetUserInfo([Description("UserInfoService.GetUserInfo name")] string name)
    {
        return new UserInfo { Name = name };
    }
}

using DescriptionAttribute = System.ComponentModel.DescriptionAttribute;
[TestFixture]
public class AttributeTests
{
    /// <summary>
    /// Reference to the Castle Windsor Container.
    /// </summary>
    public IWindsorContainer IocContainer { get; private set; }
    [SetUp]
    public void Initialize()
    {
        IocContainer = new WindsorContainer();
        IocContainer.Kernel.ProxyFactory = new CustomProxyFactory();
        IocContainer.Register(
            Component.For<UserInfoService>()
                .Proxy
                .AdditionalInterfaces(typeof(IUserInfoService))
                .LifestyleTransient()
            );

    }

    /// <summary>
    /// 
    /// </summary>
    [Test]
    public void GetAttributeTest()
    {
        var userInfoService = IocContainer.Resolve<UserInfoService>();
        Assert.IsNotNull(userInfoService);
        var type = userInfoService.GetType();
        Assert.IsTrue(type != typeof(UserInfoService));
        var attribute = type.GetCustomAttribute<DescriptionAttribute>();
        Assert.IsTrue(attribute != null);
        Trace.WriteLine(attribute.Description);

        var method = type.GetMethod("GetUserInfo");
        attribute = method.GetCustomAttribute<DescriptionAttribute>();
        Assert.IsTrue(attribute != null);
        Trace.WriteLine(attribute.Description);

        var parameter = method.GetParameters().First();
        attribute = parameter.GetCustomAttribute<DescriptionAttribute>();
        Assert.IsTrue(attribute != null);
        Trace.WriteLine(attribute.Description);
    }
}
Elisavetpol answered 31/8, 2015 at 8:43 Comment(0)
H
0

@hikalkan I faced the same problem and I was looking for a solution as well. The best I could encounter was How to add an attribute to a property at runtime

Proxy the controller (in my case a dynamic controller) with a new wrapper that set those attributes in the class itself and its methods..

Hearse answered 24/5, 2017 at 23:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.