从另一个模块调用NancyFx操作

时间:2013-11-11 12:46:04

标签: nancy

有没有办法从另一个模块中调用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....
        };
    }

3 个答案:

答案 0 :(得分:3)

正如其他评论者所指出的那样,这样做似乎是一种设计气味。无论如何......

更改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所提到的,最好的方法是将公共代码移到一个完全独立的类中,让两个模块都调用它。

答案 1 :(得分:3)

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

关于这一点的好处是它允许同一个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
}

答案 2 :(得分:1)

我同意设计一个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"]
    }; 
  }
}