0

我将这个问题作为一个单独的问题向众多其他人提出的原因是我使用 Castle Windsor 3.0 作为我的 DI 框架,因此通过 CW 的 WCF 设施配置我的端点。我无法使用此设置找到任何解决方案。


:: 更新 ::

感谢您的评论。

该项目是一个标准的 WCF 服务应用程序,它提供了许多连接到底层功能(SQl 服务器等)的标准类库。项目中存在的 Web 服务是标准的 Wcf 服务 (.svc),将托管在 IIS 中(在默认的 VS 调试服务器中测试)将由 ASP.NET MVC3 Web 应用程序使用。

这些服务在客户端和服务端都连接到 Windsor Container。

服务端:

<%@ ServiceHost 
Language="C#" 
Debug="true" 
Service="FileDownloadService" 
CodeBehind="FileDownloadService.svc.cs" 
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, 
    Castle.Facilities.WcfIntegration" %>

因此,Windsor WCFacility 负责 MVC3 应用程序和 WCF 服务应用程序中的所有依赖注入解析。

我担心配置的主要原因(我知道使用从教程/演练/SO 问题中获得的值)是因为我不确定 Windsor 是否 100% 在服务端选择此配置 - 意见?

我还更新了代码片段以显示当前的 impl。

[DataContract]
    public enum FileTypeEnum
    {
        [EnumMember]
        Generic = 1,

        [EnumMember]
        TXT = 2,

        [EnumMember]
        XLS = 3,

        [EnumMember]
        PDF = 4,

        [EnumMember]
        DOC = 5
    }

包含 WCF Web 服务的 Web 服务解决方案定义了以下协定:

[ServiceContract]
public interface IFileDownloadService
{
    [OperationContract]
     FileDownloadReturnMessage DownloadFile(FileDownloadMessage request);
}

返回类型合约是:

[MessageContract]
public class FileDownloadReturnMessage : IDisposable
{
    public FileDownloadReturnMessage(FileMetaData metaData, Stream stream)
    {
        FileByteStream = stream;
    }

    [MessageBodyMember(Order = 1)]
    public Stream FileByteStream;

    [MessageHeader(MustUnderstand = true)]
    public FileMetaData DownloadedFileMetadata;

    public void Dispose()
    {
        if (FileByteStream != null)
        {
            FileByteStream.Close();
            FileByteStream = null;
        }
    }

请求合同是:

[MessageContract]
public class FileDownloadMessage
{
    [MessageHeader(MustUnderstand = true)]
    public FileMetaData FileMetaData;
}

和:

[DataContract(Namespace = "http://schemas.acme.it/2009/04")]
public class FileMetaData
{
    public FileMetaData(string fileName, string remoteFilePath)
    {
        FileName = fileName;
        RemoteServerFilePath = remoteFilePath;
        FileType = FileTypeEnum.Generic;
    }

    public FileMetaData(string fileName, string remoteFilePath, FileTypeEnum? fileType)
    {
        FileName = fileName;
        RemoteServerFilePath = remoteFilePath;
        FileType = fileType;
    }

    [DataMember(Name = "FileType", Order = 0, IsRequired = true)]
    public FileTypeEnum? FileType;

    [DataMember(Name = "FileName", Order = 1, IsRequired = true)]
    public string FileName;

    [DataMember(Name = "RemoteFilePath", Order = 2, IsRequired = true)]
    public string RemoteServerFilePath;
}

Windsor 注入服务在服务器上的配置是:

.Register(Component.For<IFileDownloadService>()
       .ImplementedBy<FileDownloadService>()
       .Named("FileDownloadService")
       .AsWcfService(new DefaultServiceModel()
       .AddEndpoints(WcfEndpoint
              .BoundTo(new BasicHttpBinding
                   {
                       MaxReceivedMessageSize = 2147483647,
                       MaxBufferSize = 2147483647,
                       MaxBufferPoolSize = 2147483647,
                       TransferMode = TransferMode.Streamed,
                       MessageEncoding = WSMessageEncoding.Mtom,
                       ReaderQuotas = new XmlDictionaryReaderQuotas
                            {
                              MaxDepth = 2147483647,
                              MaxArrayLength = 2147483647,
                              MaxStringContentLength = 2147483647,
                              MaxNameTableCharCount = 2147483647,
                              MaxBytesPerRead = 2147483647
                            }
                   }))
              .Hosted()
              .PublishMetadata())
      .LifeStyle.PerWcfOperation())

端点的客户端配置是:

_container.Register(Component.For<IFileDownloadService>()
                    .AsWcfClient(new DefaultClientModel
                        {
                            Endpoint = WcfEndpoint
                                .BoundTo(new BasicHttpBinding
                                    {
                                        MaxReceivedMessageSize = 2147483647,
                                        MaxBufferSize = 2147483647,
                                        MaxBufferPoolSize = 2147483647,
                                        TransferMode = TransferMode.Streamed,
                                        MessageEncoding = WSMessageEncoding.Mtom,
                                        ReaderQuotas = new XmlDictionaryReaderQuotas
                                            {
                                                MaxDepth = 2147483647,
                                                MaxArrayLength = 2147483647,
                                                MaxStringContentLength = 2147483647,
                                                MaxNameTableCharCount = 2147483647,
                                                MaxBytesPerRead = 2147483647
                                            }
                                    })
                                .At(ConfigurationManager.AppSettings["FileDownloadAddress"])
                            }));

据我所知,这些端点配置必须匹配,它们确实如此。但由于某种原因,击中方法:

var commandResult = _downloadService.DownloadFile(command);

导致具有以下堆栈跟踪的异常:

Ex Message:     The remote server returned an unexpected response: (400) Bad Request.
Source:     Castle.Facilities.WcfIntegration
Target Site:    Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor+<>c__DisplayClass1 -> Void <PerformInvocation>b__0(Castle.Facilities.WcfIntegration.WcfInvocation)
Stack Trace:    at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.<>c__DisplayClass1.<PerformInvocation>b__0(WcfInvocation wcfInvocation)
   at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.ApplyChannelPipeline(Int32 policyIndex, WcfInvocation wcfInvocation, Action`1 action)
   at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.<>c__DisplayClass4.<ApplyChannelPipeline>b__3()
   at Castle.Facilities.WcfIntegration.WcfInvocation.Proceed()
   at Castle.Facilities.WcfIntegration.RepairChannelPolicy.Apply(WcfInvocation wcfInvocation)
   at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.ApplyChannelPipeline(Int32 policyIndex, WcfInvocation wcfInvocation, Action`1 action)
   at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.PerformInvocation(IInvocation invocation, IWcfChannelHolder channelHolder, Action`1 action)
   at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.PerformInvocation(IInvocation invocation, IWcfChannelHolder channelHolder)
   at Castle.Facilities.WcfIntegration.Async.WcfRemotingAsyncInterceptor.PerformInvocation(IInvocation invocation, IWcfChannelHolder channelHolder)
   at Castle.Facilities.WcfIntegration.Proxy.WcfRemotingInterceptor.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.IWcfChannelHolderProxy_2.FakeDownloadTest(FakeDownloadTestRequest request)
   at cpfe.DAL.Repositories.FileDownloadRepository.DownloadFile(IEnumerable`1 fileIds, TenantDTO tenant, String zipPackageName, UserDTO user) \..\..\..\FileDownloadRepository.cs:line 44

有人知道为什么会这样吗?

提前致谢!

4

3 回答 3

2

我认为您不能在消息正文中传输 Stream 和其他数据。您需要使用 MessageContract 在消息的标头中添加自定义数据,并在正文中添加流。

您需要使用特定的合同。您可以使用带有 messagecontract 的类来封装您当前的合同。像这样 :

[ServiceContract]
public interface IFileDownloadService
{
    [OperationContract]
    StreamResponse DownloadFile(DownloadFileCommandRequest command);
}

[MessageContract]
public class StreamResponse
{
    [MessageHeader()]
    public CommandResult<FileDownloadDTO> {get; set;}

    [MessageBodyMember(Order = 1)]
    public Stream FileByteStream { get; set; }
}

[MessageContract]
public class DownloadFileCommandRequest 
{
    [MessageBodyMember(Order = 1)]
    public DownloadFileCommand FileCommand {get; set;}
}

并删除 FileDownloadDTO 类中的流属性。也许如果您只删除 DataMember 属性就可以了。

[DataContract]
public class FileDownloadDTO : IDisposable, IDTOBase
{
   [DataMember]
   public string FileName { get; set; }

   [DataMember]
   public long Length { get; set; }

   [DataMember]
   public int Id { get; set; }
}

这里是客户端配置的示例。

<binding name="FileHttpBinding"  closeTimeout="04:01:00"
                openTimeout="04:01:00" receiveTimeout="04:10:00" sendTimeout="04:01:00"
                allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
                transferMode="Streamed" messageEncoding="Mtom">
                <readerQuotas maxDepth="128" maxStringContentLength="2147483647" maxArrayLength="2147483647"
                        maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
                <security mode="None">
                </security>
            </binding>
于 2012-06-26T10:12:57.583 回答
2

我重现了 400 错误,在对代码进行了一些更改后它就消失了:

  1. 使用TransferMode = TransferMode.StreamedResponse,而不是Streamed. 我仅将其应用于客户端配置。服务器还有Streamed
  2. 将默认(无参数)构造函数添加到FileDownloadReturnMessage. 这是MessageContract反序列化所必需的。代码 -public FileDownloadReturnMessage() { }

有趣的是,现在我无法重现错误,即使使用TransferMode.Streamed

让我知道这是否有帮助。

如果您仍然无法解决问题,我可以发布我的代码。

有趣的是客户端中的 WCF 会生成 400 错误。如果您在 fiddler 中检查流量,服务器总是返回 200 和正确的数据。

于 2012-06-26T17:49:55.350 回答
0

请在服务端检查您的连接字符串。如果您在连接字符串中使用 Windows 身份验证,请尝试通过为您的数据库创建 sql 用户来使用 SQL 身份验证

于 2012-06-25T10:51:42.393 回答