Search code examples
c#wcfstreammessagecontractwcf-streaming

WCF Webservice pass messagecontract with Stream and return a string to Client


I want to create WCF web service to recalculate the formula of .xlsx and .xls files(want to determine the extension type in service and return back processed fileID back to client and then another service method to get file from the returned fileID

enter image description here

But I didn’t able to Achieve my 1st method.

I created my service as below

Object/ MessageContract

[MessageContract]
    public class UploadStreamMessage
    {
        [MessageHeader]
        public string fileName;
        [MessageBodyMember]
        public Stream fileContents;
    }

Interface

[OperationContract]
[WebInvoke(UriTemplate = "/UploadFile")]
string UploadFile(UploadStreamMessage message);

[OperationContract]
Stream ReturnFile(string GUID);

Service method

public string UploadFile(UploadStreamMessage message)
{
   string FileId = Guid.NewGuid().ToString();
   //Get fie stream and determin the extension type and save in server and return Saved file Id
   return FileId;
}
public Stream ReturnFile(string GUID)
{
   Stream generatedFileStream = null;
   //Get fie using Id and create stream and send back
   return generatedFileStream;
}

Web.Config

<bindings>
        <webHttpBinding>
            <binding name="webHttpBinding" transferMode="Streamed"/>
        </webHttpBinding>
    </bindings>
    <behaviors>
        <endpointBehaviors>
            <behavior name="webHttpBehavior">
                <webHttp/>
            </behavior>
        </endpointBehaviors>
        <serviceBehaviors>
            <behavior>
                <!--<behavior name="ServiceBehavior">-->
                <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
                <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
                <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                <serviceDebug includeExceptionDetailInFaults="true"/>
                <serviceThrottling maxConcurrentCalls="2147483647"  maxConcurrentSessions="2147483647"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

Expectation: ReturnFile : worked and result as expected UploadFile : When I try to run UploadFile method below exception occurred.

The operation 'UploadFile' could not be loaded because it has a parameter or return type of type System.ServiceModel.Channels.Message or a type that has MessageContractAttribute and other parameters of different types. When using System.ServiceModel.Channels.Message or types with MessageContractAttribute, the method must not use any other types of parameters. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

So I wend through the Stackoverflow and found below threads How to return value using WCF's MessageContract? , WCF - Return Object With Stream Data , Use of MessageContract crashes WCF service on startup and found I cannot return back string value while send message contract but can return another MessageContract.through web service method.

So I changed my code as below Added a new param(returnFileName) to Message contract, I need to return to the client :

[MessageContract]
    public class UploadStreamMessage
    {
        [MessageHeader]
        public string fileName;
        [MessageBodyMember]
        public Stream fileContents;
        [MessageHeader]
        public string returnFileName;
    }

Interface and method as below : Interface :

[OperationContract]
        [WebInvoke(UriTemplate = "/UploadFile")]
        UploadStreamMessage UploadFile(UploadStreamMessage message);

Service method:

public UploadStreamMessage UploadFile(UploadStreamMessage message)
        {
            message.returnFileName = Guid.NewGuid().ToString();
            string FileId = Guid.NewGuid().ToString();
            //Get fie stream and determin the extension type and save in server and return Saved file Id
            return message;
        }

Client Appication:

static void Main(string[] args)
        {
            ServiceReferenceFile.FileServiceClient Client = new ServiceReferenceFile.FileServiceClient();
            ServiceReferenceFile.UploadStreamMessage message = new ServiceReferenceFile.UploadStreamMessage();
            string fileName = "FileName", outputFile ="";
            Stream str = File.OpenRead("DummyDataFile.xlsx");
            message = Client.UploadFile(ref fileName, ref outputFile, ref str);
        }

But still it provides me error and it doesn’t allow to get return object :

Cannot implicitly convert type 'void' to 'ConsoleAppFileAction.ServiceReferenceFile.UploadStreamMessage'

Please someone tell me what is the error im doing ?


Solution

  • I was able to manage the code according to @Steeeve instructions and result get as expected. Objects/ MessageContracts

    [MessageContract]
    //It is same as UploadStreamMessage
    public class UploadFileRequest
    {
      [MessageHeader]
      public string fileName;
    
      [MessageBodyMember]
      public Stream fileContents;
    }
    
    [MessageContract]
    public class UploadFileResponse
    {
      [MessageBodyMember]
      public string ProcessedFileName;
    
      [MessageBodyMember]
      public string ProcessedFileNameDetails;
    }
    

    Interface:

    [OperationContract]
    UploadFileResponse UploadFile(UploadFileRequest message);
    

    Service Method

    public UploadFileResponse UploadFile(UploadFileRequest fileRequest)
    {
      UploadFileResponse resp = new UploadFileResponse();
      LogicClass logics = new LogicClass();
      resp.ProcessedFileNameDetails = logics.GetExcelFileMain(fileRequest);
      return resp;
    }
    

    Client Application : Webservice returned file name able to get as outparameter.

    ServiceReferenceExcelRefersh.FileServiceClient fileServiceClient = new ServiceReferenceExcelRefersh.FileServiceClient();
        
    fileServiceClient.UploadFile(fileName, fileStream, out string ProcessedFileNameDetails);