I have a WCF Service that based on Writing Highly Maintainable WCF Services. Requests are processed using a CommandService:
[WcfDispatchBehaviour]
[ServiceContract(Namespace="http://somewhere.co.nz/NapaWcfService/2013/11")]
[ServiceKnownType("GetKnownTypes")]
public class CommandService
{
[OperationContract]
public object Execute(dynamic command)
{
Type commandHandlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
dynamic commandHandler = BootStrapper.GetInstance(commandHandlerType);
commandHandler.Handle(command);
return command;
}
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
var coreAssembly = typeof(ICommandHandler<>).Assembly;
var commandTypes =
from type in coreAssembly.GetExportedTypes()
where type.Name.EndsWith("Command")
select type;
return commandTypes.ToArray();
}
}
Everything works great (thanks Steve) but now I need to add the ability to upload a file to the service. From what I've read and based on errors received during testing, WCF needs to use a [MessageContract]
when uploading a file using a Stream
. So I've decorated my command class and put the non-Stream members into the message header, and updated my binding definition to use streaming:
[MessageContract]
public class AddScadaTileCommand
{
[MessageHeader(MustUnderstand = true)]
public int JobId { get; set; }
[MessageHeader(MustUnderstand = true)]
public string MimeType { get; set; }
[MessageHeader(MustUnderstand = true)]
public string Name { get; set; }
[MessageBodyMember(Order = 1)]
public Stream Content { get; set; }
}
Unfortunately when I call the service with a file to upload I get an error:
There was an error while trying to serialize parameter http://somewhere.co.nz/NapaWcfService/2013/11:command. The InnerException message was 'Type 'System.IO.FileStream' with data contract name 'FileStream:http://schemas.datacontract.org/2004/07/System.IO' is not expected.
So I added a new method to the service specifically for the file upload request:
[OperationContract]
public void Upload(AddScadaTileCommand addScadaTileCommand)
{
Type commandHandlerType = typeof(ICommandHandler<>).MakeGenericType(typeof(AddScadaTileCommand));
dynamic commandHandler = BootStrapper.GetInstance(commandHandlerType);
commandHandler.Handle(addScadaTileCommand);
}
This works perfectly, unless I change the AddScadaTileCommand
parameter to dynamic
in the method definition, in which case I get the same error as above. This appears to indicate that the [MessageContract]
attributes are not applied or ignored when using dynamic
as the type of the parameter. Is there any way to resolve this or will I need to create separate methods for requests that involve streams?