C# 如何在Azure移动应用程序服务客户端中实现AOP?

C# 如何在Azure移动应用程序服务客户端中实现AOP?,c#,xamarin,aop,custom-attributes,azure-app-service-envrmnt,C#,Xamarin,Aop,Custom Attributes,Azure App Service Envrmnt,在使用MVC 5、Web API 2.0和EF Core 1.0的Azure Mobile App Services服务器端应用程序上,可以对控制器进行这样的修饰,以实现基于令牌的身份验证: // Server-side EF Core 1.0 / Web API 2 REST API [Authorize] public class TodoItemController : TableController<TodoItem> { protected override void

在使用MVC 5、Web API 2.0和EF Core 1.0的Azure Mobile App Services服务器端应用程序上,可以对控制器进行这样的修饰,以实现基于令牌的身份验证:

// Server-side EF Core 1.0 / Web API 2 REST API
[Authorize]
public class TodoItemController : TableController<TodoItem>
{
  protected override void Initialize(HttpControllerContext controllerContext)
  {
     base.Initialize(controllerContext);

     DomainManager = new EntityDomainManager<TodoItem>(context, Request);
  }

  // GET tables/TodoItem
  public IQueryable<TodoItem> GetAllTodoItems()
  {
     return Query();
  }
  ...
}
不幸的是,根据Microsoft关于“创建自定义操作筛选器”的文章,上述代码仅适用于MVC 1.0及以上应用程序中的控制器:

如何实现“自定义操作过滤器”之类的功能,允许我在移动应用程序服务客户端而不是服务器中使用“[安全]”装饰?答案将帮助我从客户端创建自定义身份验证,并将代码保存在一个位置,而不会使实现复杂化,即,这是一个交叉问题,如性能指标、重复尝试的自定义执行计划、日志记录等


使场景复杂化的是,客户端还实现了Xamarin.Forms for iOS,并且由于iOS对本机代码的要求,必须是一种功能性的提前模式,JIT还不可能实现。

您通常用几个不同的名称/术语来描述的内容。首先想到的是“面向方面编程”(简称AOP)。它处理的是我们所知道的。我敢打赌你想做两件事中的一件

  • 以标准化且有意义的方式记录异常/消息
  • 记录系统各区域的时间/性能
  • 在一般意义上,是的,C#能够做这些事情。关于如何做到这一点,将会有无数的在线教程,用这种方式回答太广泛了

    然而,asp.net MVC的作者对这些问题有着非常深入的思考,并向您提供了许多您所描述的属性,这些属性可以根据您的意愿进行扩展,并且可以方便地访问管道,为开发人员提供他们所需的所有信息(如当前路由、任何参数、任何异常、任何授权/身份验证请求等)

    这将是一个很好的起点:


    这看起来也不错:

    属性在您描述的场景中起作用的原因是其他代码负责实际调用方法或读取属性,而其他代码将查找属性并相应地修改行为。当您只是运行C代码时,通常不会得到这一点;没有n例如,在执行方法之前执行属性中的代码

    从您描述的内容来看,您似乎在追求面向方面的编程。有关框架列表,请参阅

    本质上,使用适当的AOP框架,您可以添加属性或其他标记,并在编译时执行或插入代码。 您确实需要了解AOP方法与ASP.NETMVC的工作方式不同,因为AOP通常会修改您的运行时代码(以我的理解,我确信这方面也有变化)

    至于AOP是否真的是一条路,这将取决于你的要求,但我会谨慎行事——这不适合胆小的人

    解决这个问题的一个完全可供选择的方法是,研究类似或类似的方法,将逻辑分解为一组命令,您可以通过消息总线调用这些命令。这样做的原因是您可以修饰消息总线(或管道)具有各种类型的逻辑,包括授权逻辑。该解决方案与您所要求的非常不同,但可能更可取


    或者只是在每个方法的第一行添加一个单行授权调用,而不是将其作为一个属性…

    您是否考虑过根据自己的需要扩展自定义授权???我不知道如何做。您所说的“扩展自定义授权”是什么意思这是客户端,所以我假设你指的是LoginAsync。这些都是很好的想法,我可以将其用于日志和性能指标。目前,我的目的是用于客户端自定义身份验证(尝试/捕获检查HTTP unauthorized,然后在必要时显示登录模式)。不幸的是,Azure Mobile App Services中用于授权的AOP内容似乎是为服务器端的MVC 5+设计的,并且只内置于LoginAsync中(而不是自定义身份验证)在客户端。我试图在不使用MVC 5+的客户端上构建此包装器,因此我对LoginAsync没有“未知”和移动目标依赖性。我希望将客户端方法包装为某种通用的try/catch,以捕获MobileServiceInvalidOperationException,然后在自定义execut中重试执行离子计划(即,在UI中显示错误之前,3次尝试击中Azure)。解决方案使用Xamarin.Forms实现跨平台兼容性,因此我在这方面也受到限制。我将研究您的建议,谢谢。我对该问题采取的一种方法是静态方法,该方法采用lambda,然后尝试执行该lambda,重试并捕获异常等。您仍然必须实际使用该方法,但总比重复它好。但是,mediatr实际上可能是一个不错的选择,因为你可以通过管道上的装饰器来处理这一点。它看起来像PostSharp支持Xamarin(和IOS),这里有一个链接,指向那些正在寻找我正试图做的事情的人:不幸的是,PostSharp是一个商业产品
    public class TodoItem
    {
        string id;
        string name;
        bool done;
    
        [JsonProperty(PropertyName = "id")]
        public string Id
        {
            get { return id; }
            set { id = value;}
        }
    
        [JsonProperty(PropertyName = "text")]
        public string Name
        {
            get { return name; }
            set { name = value;}
        }
    
        [JsonProperty(PropertyName = "complete")]
        public bool Done
        {
            get { return done; }
            set { done = value;}
        }
    
        [Version]
        public string Version { get; set; }
    }
    
    // Client side code calling GetAllTodoItems from above
    [Secured]
    public async Task<ObservableCollection<TodoItem>> GetTodoItemsAsync()
    {
        try
        {
            IEnumerable<TodoItem> items = await todoTable
                .Where(todoItem => !todoItem.Done)
                .ToEnumerableAsync();
    
            return new ObservableCollection<TodoItem>(items);
        }
        catch (MobileServiceInvalidOperationException msioe)
        {
            Debug.WriteLine(@"Invalid sync operation: {0}", msioe. 
        }
        catch (Exception e)
        {
            Debug.WriteLine(@"Sync error: {0}", e.Message);
        }
    
        return null;
    }
    
    public class SecuredFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Check if user is logged in, if not, redirect to the login page.
        }
    
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            // Check some globally accessible member to see if user is logged out.
        }
    }