简体   繁体   English

从另一个服务中调用一个ServiceStack 4服务,并抛出文件上传的乐趣

[英]Calling one ServiceStack 4 service from another with a file upload thrown in for fun

I have a working service in 4.0.31 that looks like this: 我在4.0.31中有一个工作服务,看起来像这样:

public object Post(MyDTO request)
{
   foreach (var uploadedFile in base.Request.Files)
   {
      ... do something ...
   }
   return new MyDTOResponse();
}

Everything works great, and I'm happy! 一切都很好,我很高兴!

But now, I want to call the same service method from within another service, the way to do this apparently is: 但是现在,我想从另一个服务中调用相同的服务方法,显然,这样做的方法是:

public object Post(MyOtherDTO request)
{
  var myService = base.ResolveService<MyService>();
  // now I call some new method I wrote to bypass the file upload part, since
  // myService.Post() doesn't know about the file upload part
  var myResponse = myService.NewMethodThatLetsMePassAStreamToTheOtherService(streamData);
  ... do other stuff...
  return new MyOtherDTOResponse();
}

While I'm not unhappy with this, it does create a hard dependency between the two services, so I'm not thrilled like I usually am with ServiceStack! 虽然我对此并不满意 ,但它确实在两个服务之间创建了硬依赖性,因此,我并不像通常使用ServiceStack那样激动

Is there a more elegant way of putting this together? 有没有更优雅的方式将它们组合在一起? I'm probably just missing something really, really obvious... 我可能只是想念一些非常非常明显的东西...

I'm not 100% clear on what the issue is, if it's how to share logic between services? 我不清楚问题是什么,如果要在服务之间共享逻辑的话? then you could pull common logic out of each service class and reference the shared code in both Services. 那么您可以从每个服务类中提取通用逻辑,并在两个服务中引用共享代码。

If no dependencies are required I'll refactor the shared code behind re-usable extension methods . 如果不需要依赖,我将在可重用的扩展方法后面重构共享代码。

If dependencies are required I will refactor it behind a shared logic class that's a dependency in both Services, see the IGreeter example in the sharing logic between MVC and ServiceStack answer : 如果需要依赖关系,我将在两个服务都依赖的共享逻辑类后面重构它,请参阅MVC和ServiceStack之间共享逻辑中IGreeter示例:

public class MyService1 : Service
{
    public ISharedDep SharedDep { get; set] 

    public object Any(Request1 request)
    {
        //...
    }
}

public class MyService2 : Service
{
    public ISharedDep SharedDep { get; set] 

    public object Any(Request2 request)
    {
        //...
    }
}

Shared logic using Request Context using base class 使用基类使用请求上下文的共享逻辑

If it's common code used by many Services that requires the base.Request context than you could move it to a common Service base class: 如果是许多需要base.Request上下文的服务使用的通用代码,则可以将其移至通用Service基类:

public class MyServiceBase : Service
{
    public ISharedDep SharedDep { get; set] 

    public object SharedMethod(object request)
    {
        //...
    }
}

public class MyServices1 : MyServiceBase { ... }
public class MyServices2 : MyServiceBase { ... }

Shared logic using Request Context using Extension method 使用扩展方法使用请求上下文的共享逻辑

If you prefer not to use a base class, this can be re-factored behind an extension method as well: 如果您不想使用基类,则也可以在扩展方法后面对其进行重构:

public static void MyServiceExtensions
{
    public static object SharedMethod(this IServicBase service, object request)
    {
        var sharedDep = service.TryResolve<ISharedDep>();
        return sharedDep.SharedMethodWithRequestCtx(request, service.Request);
    }
}

Loose Coupling by executing a Request DTO 通过执行请求DTO松散耦合

If the issue is about a loose-coupled way to call Services without a reference to the implementation itself you can execute the Request DTO with the ServiceController: 如果问题是关于调用服务的松散耦合方式而不涉及实现本身,则可以使用ServiceController执行Request DTO:

public class MyService : Service
{
    public object Any(Request requestDto)
    {
        var altDto = new AltRequest { Id = requestDto.Id };
        var response = HostContext.ServiceController.Execute(altDto, base.Request);
        //...
    }
}

Note: this API is available as base.ExecuteRequest(requestDto) in v4.0.32+. 注意:此API在v4.0.32 +中可以作为base.ExecuteRequest(requestDto)使用。

Uploading Files to a HTTP Service In Memory 将文件上传到内存中的HTTP服务

If the issue is instead how to execute a Service that handles file uploads, there's an example in the embedded version of HttpBenchmarks showing how to call a Service that processes HTTP File uploads with a custom Request Context that uses local FileSystem files instead: 如果问题是如何执行处理文件上传的服务, 则嵌入式版本的HttpBenchmarks中有一个示例,该示例显示如何调用使用自定义请求上下文(使用本地FileSystem文件)来处理HTTP文件上传的服务:

using (var admin = Resolve<AdminServices>())
{
    //...
    var dir = new FileSystemVirtualPathProvider(this, Config.WebHostPhysicalPath);
    var files = dir.GetAllMatchingFiles("*.txt")
        .Concat(dir.GetAllMatchingFiles("*.zip"));

    admin.Request = new BasicRequest
    {
        Files = files.Map(x => new HttpFile {
            ContentLength = x.Length,
            ContentType = MimeTypes.GetMimeType(x.Name),
            FileName = x.Name,
            InputStream = x.OpenRead(),
        } as IHttpFile).ToArray()
    };

    if (admin.Request.Files.Length > 0)
    {
        admin.Post(new UploadTestResults
        {
            TestPlanId = 1,
            TestRunId = testRun.Id,
            CreateNewTestRuns = true,
        });
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM