【问题标题】:Call NancyFx action from another module从另一个模块调用 NancyFx 操作
【发布时间】:2017-04-22 03:10:03
【问题描述】:

有没有办法从另一个模块中调用 NancyFX 动作?

public class FirstModule : NancyModule
{
    public FirstModule()
    {

        Post["/FirstMethod/{id}"] = parameters =>
        {
            var response =  <Call second module and SecondMethod>;
            return View["blah"]
        }; 
    }
}

然后调用第二个模块的方法:

public class SecondModule : NancyModule
{
    public SecondModule()
    {
        Post["SecondMethod/{id}"] = parameters =>
        {
            Do some stuff....
        };
    }

【问题讨论】:

  • 听起来您想将“SecondMehod”的实现推入另一个对象,两个模块都可以依赖并调用它。
  • 您为什么要这样做?如果您需要从另一个调用 1 个模块路由,那么您的设计是错误的。说明您要达到的目标,也许我们可以提出更好的解决方案。
  • 是的,我同意这是糟糕的设计。第二个 nancy 模块是一个安静的服务。第一个是一个单独的 dll 中的网站,我想从中调用 resful 服务 api。

标签: nancy


【解决方案1】:

正如其他评论者所指出的,这样做似乎有点设计味道。无论如何...

如下更改 SecondModule 的代码:

public class SecondModule : NancyModule
{
    public SecondModule()
    {
        Post["SecondMethod/{id}"] = SecondMethod;
    }

    public object SecondMethod(dynamic p)
    {
        //Do some stuff...
    }

然后在您的第一个模块中,只需根据需要调用第二个模块:

Post["/FirstMethod/{id}"] = parameters =>
{
    var secondModule = new SecondModule(); //use dependency injection in real code 
    var response =  secondModule.SecondMethod(parameters);
    return View["blah"]
}; 

当然,正如@Christian 所提到的,最好的方法是将通用代码移到一个完全独立的类中,并让两个模块都调用它。

【讨论】:

  • 肯定是臭设计。感谢您的帮助。
【解决方案2】:

我正在寻找如何将控制从一个动作传递到另一个模块中的另一个动作,这是我得到的最接近实际答案的方法。以防万一它对其他人有所帮助,这是我发现的一般情况。

这样做的好处是它允许通过同一个 url 访问多个模块中的多个操作,但会将内容封装在最合乎逻辑的位置。

在源(传递控制的那个)动作中:

public class IndexModule : BaseModule
{
    public IndexModule()
    {
        Get["/"] = parameters =>
        {
            // Here we want to handoff to the default action in another module; this keeps the URL the same
            var itemController = new DbItemModule { Context = this.Context };
            parameters.itemId = 5; // Specific item to load in target
            return itemController.itemHomeSharedLogic(parameters);
        }
    }
}

在目标模块中:

public class DbItemModule : BaseModule
{
    public GeneralModule() : base("/item")
    {
        Get["/{itemId}"] = parameters => itemHomeSharedLogic(parameters);
    }

    /// <summary>
    /// This is factored out of the /item/{itemId} route so it can be shared with IndexModule's default route.
    /// </summary>
    /// <param name="parameters">Object with (int)itemId property set for the item to show.</param>
    /// <returns>Value of the GET action handler for an item's homepage.</returns>
    ///
    public Negotiator itemHomeSharedLogic(dynamic parameters)
    {
        dynamic model = new ExpandoObject();
        // ...set model properties...

        return View["db/item/index", model];

    } // itemHomeSharedLogic
}

【讨论】:

    【解决方案3】:

    我同意设计一个 Nancy 应用程序,其中一个路由需要直接调用另一个路由是不好的做法。但是,我有一个相关但不同的场景。我有一个应用程序,其中许多路由代表数据库中的项目。这些路由可能采用/{type}/{guidPrimaryKey}/{type}/{humanReadableKey} 甚至/{type}/{humanReadableKey}/rev/{revision} 的形式。考虑一个表单,用户需要告诉服务器要使用数据库中的哪个项目。除了搜索功能之外,我希望用户能够粘贴代表数据库项目的 URL。我不希望在多个位置拥有所有不同 URL 结构的代码逻辑,因此最好将 URL 作为参数传递给一个路由并从它所代表的路由中获取响应。经过一番破解,我找到了一个可行的解决方案。

    创建一个类来计算依赖于核心 Nancy 路由接口的响应

    public class UrlDispatcher
    {
      private IRequestDispatcher _dispatcher;
      private INancyContextFactory _contextFactory;
    
      public UrlDispatcher(IRequestDispatcher dispatcher
        , INancyContextFactory contextFactory)
      {
        _dispatcher = dispatcher;
        _contextFactory = contextFactory;
      }
    
      public async Task<Response> GetResponse(NancyContext context
        , string url, CancellationToken ct)
      {
        var request = new Request("GET", new Url(url), null
          , context.Request.Headers.ToDictionary(k => k.Key, k => k.Value));
        var ctx = _contextFactory.Create(request);
        return _dispatcher.Dispatch(ctx, ct);
      }
    }
    

    在您的bootstrapper class 中,实例化并存储 此实用程序类的副本

    public class Bootstrapper : Nancy.Hosting.Aspnet.DefaultNancyAspNetBootstrapper
    {
      private static UrlDispatcher _dispatcher;
      public static UrlDispatcher Dispatcher { get { return _dispatcher; } }
    
      protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container
        , Nancy.Bootstrapper.IPipelines pipelines)
      {
        base.ApplicationStartup(container, pipelines);
        _dispatcher = container.Resolve<UrlDispatcher>();
      }
    }
    

    然后,从您的模块中,代码看起来像

    public class FirstModule : NancyModule
    {
      public FirstModule()
      {
        Post["/FirstMethod/{id}", true] = async (parameters, ct) =>
        {
          var response = await Bootstrapper.Dispatcher.GetResponse(this.Context
            , "http://test/SecondMethod/" + (string)parameters.id, ct);
          return View["blah"]
        }; 
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2020-03-10
      • 1970-01-01
      • 2018-11-22
      • 2018-10-01
      • 1970-01-01
      • 2018-05-02
      相关资源
      最近更新 更多