[ServiceContract(Namespace = "http://www.guruetech.com")]
public interface IService
{
[OperationContract]
UploadResult Upload(Stream itemStream); // succeeded!
[OperationContract]
UploadResult Upload(Stream itemStream, string theParameter); // failed!!!
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
public class Service : IService
{
public UploadResult Upload(Stream itemStream)
{
}
public UploadResult Upload(Stream itemStream, string theParameter) { } // failed!!!
}
From MSDN Streaming Message Transfer
"Restrictions on Streamed Transfers
Using the streamed transfer mode causes the run time to enforce additional restrictions.
Operations that occur across a streamed transport can have a contract with at most one input or output parameter."
Related
is it possible to call a service operation at a wcf endpoint uri with a self hosted service?
I want to call some default service operation when the client enters the endpoint uri of the service.
In the following sample these uris correctly call the declared operations (SayHello, SayHi):
- http://localhost:4711/clerk/hello
- http://localhost:4711/clerk/hi
But the uri
- http://localhost:4711/clerk
does not call the declared SayWelcome operation. Instead it leads to the well known 'Metadata publishing disabled' page. Enabling mex does not help, in this case the mex page is shown at the endpoint uri.
private void StartSampleServiceHost()
{
ServiceHost serviceHost = new ServiceHost(typeof(Clerk), new Uri( "http://localhost:4711/clerk/"));
ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(typeof(IClerk), new WebHttpBinding(), "");
endpoint.Behaviors.Add(new WebHttpBehavior());
serviceHost.Open();
}
[ServiceContract]
public interface IClerk
{
[OperationContract, WebGet(UriTemplate = "")]
Stream SayWelcome();
[OperationContract, WebGet(UriTemplate = "/hello/")]
Stream SayHello();
[OperationContract, WebGet(UriTemplate = "/hi/")]
Stream SayHi();
}
public class Clerk : IClerk
{
public Stream SayWelcome() { return Say("welcome"); }
public Stream SayHello() { return Say("hello"); }
public Stream SayHi() { return Say("hi"); }
private Stream Say(string what)
{
string page = #"<html><body>" + what + "</body></html>";
return new MemoryStream(Encoding.UTF8.GetBytes(page));
}
}
Is there any way to disable the mex handling and to enable a declared operation instead?
Thanks in advance, Dieter
Did you try?
[OperationContract, WebGet(UriTemplate = "/")]
Stream SayWelcome();
UPDATE:
Not sure why it is not working for you, I have a self hosted WCF service with the following service contract:
[ServiceContract]
public interface IDiscoveryService {
[OperationContract]
[WebGet(BodyStyle=WebMessageBodyStyle.Bare, UriTemplate="")]
Stream GetDatasets();
The only difference I can see is that I use WebServiceHost instead of ServiceHost.
I am aware that there is a similar question here with no solution.
I'm working on a WCF streaming service over HTTP.
Here are my MessageContract
[MessageContract]
public class FileRequest
{
#region Message Header
[MessageHeader(MustUnderstand = true)]
public Credential Credentials { get; set; }
#endregion
#region Message body
[MessageBodyMember(Order = 1)]
public FileInfo FileInfo { get; set; }
#endregion
#region Ctor
// ...
#endregion
}
[MessageContract]
public class FileRequestResponse
{
#region Message Header
[MessageHeader(MustUnderstand = true)]
public FileInfo FileHeader { get; set; }
[MessageHeader(MustUnderstand = true)]
public OperationResult<bool> OperationResult { get; set; }
#endregion
#region Message Body
[MessageBodyMember]
public Stream FileStream { get; set; }
#endregion
#region Constructor
// ...
#endregion
}
Here is my ServiceContract
[ServiceContract(Namespace = "https://service.contract.example.com")]
public interface IUpdateService
{
[OperationContract(Action = "GetUpdates")]
OperationResult<List<FileInfo>> GetUpates(ApplicationInfo applicationInfo, Credential credential);
[OperationContract(Action = "GetFile")]
FileRequestResponse FileRequest(FileRequest fileRequest);
}
Now the question is why I am getting this error:
// CODEGEN: Generating message
contract since message FileRequest has
headers
When I add my service reference. The end result is that the service contract wraps the FileRequest operation into a wrapper which I do not want.
public FileInfo FileRequest(Credential Credentials, FileInfo, out OperationResult<bool> OperationResult, out System.IO.Stream FileStream)
NOTE:
I have not checked the "Always generate message contracts" in the service reference.
Set [MessageContract(IsWrapped=true)] for all the message contracts in the service and then try generating the proxy .
You might want to try to use the IsWrapped attribute on the message contract:
[MessageContract(IsWrapped=false)]
Not 100% sure which one you'll need (true or false) but that's one of the options you could try.
Also, another observation: I think it's a bit risky to have a method called FileRequest and a message contract which also is called FileRequest.
The generally accepted best practive would be to have a method GetFile, a request message for that called GetFileRequest and a response message type GetFileResponse. Do not use the same names for different things.
I am interested in impersonating well-known Web Services and Wcf Services for integration test purposes. To this end, I would like to capture service metadata, auto-generate service stubs, and host service stubs in a self-hosted environment.
Following this article here, I am able to obtain remote Wcf Service metadata and generate contracts. However, I am having some difficulty doing the same for remote Asmx Web Services.
I have a set of mickey-mouse solutions for vetting this out.
My Asmx solution contains a default "Hello World" web service, found below
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class SimpleAsmxService : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld () { return "Hello World"; }
}
My Wcf solution contains a default "Hello World" service, also found below
[ServiceContract]
public interface ISimpleWcfService
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}
[DataContract]
public class CompositeType
{
[DataMember]
public bool BoolValue { get; set; }
[DataMember]
public string StringValue { get; set; }
}
public class SimpleWcfService : ISimpleWcfService
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Finally, the little console-that-could looks like
class Program
{
public const string UrlWcf =
"http://localhost:8731/Design_Time_Addresses/SimpleWcfService/mex";
public const string UrlAsmx =
"http://localhost:1803/SimpleAsmxService.asmx?WSDL";
static void Main(string[] args)
{
EndpointAddress mexAddress = new EndpointAddress (UrlWcf);
MetadataExchangeClient mexClient =
new MetadataExchangeClient (mexAddress);
mexClient.ResolveMetadataReferences = true;
// NOTE: blows up if we use UrlAsmx
MetadataSet metaSet = mexClient.GetMetadata ();
WsdlImporter importer = new WsdlImporter (metaSet);
Collection<ContractDescription> contracts =
importer.ImportAllContracts();
}
}
It seems to me that I should be able to pull Wsdl from a well-known Asmx Web Service and generate contracts [and from contracts to code], but cannot seem to contort the preceding sample to do so. Any help would be much appreciated,
Thanks!
NOTE: the error generated when invoking MetadataSet metaSet = mexClient.GetMetadata(); above is a System.InvalidOperationException with message of
Metadata contains a reference that cannot be resolved : 'http://localhost:1803/SimpleAsmxService.asmx?WSDL'
With a System.InvalidOperationException inner exception with message of
<?xml version="1.0" encoding="utf-16"?>
<Fault xmlns="http://www.w3.org/2003/05/soap-envelope">
<Code>
<Value>Sender</Value>
</Code>
<Reason>
<Text xml:lang="en">
System.Web.Services.Protocols.SoapException: Unable to handle request without a valid action parameter. Please supply a valid soap action.
at System.Web.Services.Protocols.Soap12ServerProtocolHelper.RouteRequest()
at System.Web.Services.Protocols.SoapServerProtocol.RouteRequest(SoapServerMessage message)
at System.Web.Services.Protocols.SoapServerProtocol.Initialize()
at System.Web.Services.Protocols.ServerProtocol.SetContext(Type type, HttpContext context, HttpRequest request, HttpResponse response)
at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type, HttpContext context, HttpRequest request, HttpResponse response, Boolean& abortProcessing)
</Text>
</Reason>
</Fault>
The way to get it to work with an ASMX web service is to specify the MetadataExchangeClientMode
...
MetadataExchangeClient mexClient =
new MetadataExchangeClient (new Uri(), MetadataExchangeClientMode.HttpGet);
...
using MetadataExchangeClientMode.HttpGet for your ASMX services
and MetadataExchangeClientMode.MetadataExchange for your WCF services.
I have a WCF service hosted in a Windows service.
I've added to it a webHttpBinding with a webHttp behaviour and whenever I send it a GET request I get http 200 which is what I want, problem is I get an http 405 whenever I send it a HEAD request.
Is there a way to make it return http 200 also for HEAD?
Is that even possible?
edit: that's the operation contract:
[OperationContract]
[WebGet(UriTemplate = "MyUri")]
Stream MyContract();
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(UriTemplate="/data")]
string GetData();
}
public class Service : IService
{
#region IService Members
public string GetData()
{
return "Hello";
}
#endregion
}
public class Program
{
static void Main(string[] args)
{
WebHttpBinding binding = new WebHttpBinding();
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri("http://localhost:9876/MyService"));
host.AddServiceEndpoint(typeof(IService), binding, "http://localhost:9876/MyService");
host.Open();
Console.Read();
}
}
The above code works fine. I get a 405 (Method not allowed) on HEAD request. The version of assembly I am using is System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35.
Actually as far as I know there is no straight forward way of allowing it.However you could try something like the solution below..But this has to be done for each method that needs GET and HEAD, which makes it a not so elegant solution..
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "*", UriTemplate = "/data")]
string GetData();
}
public class Service : IService
{
#region IService Members
public string GetData()
{
HttpRequestMessageProperty request =
System.ServiceModel.OperationContext.Current.IncomingMessageProperties["httpRequest"] as HttpRequestMessageProperty;
if (request != null)
{
if (request.Method != "GET" || request.Method != "HEAD")
{
//Return a 405 here.
}
}
return "Hello";
}
#endregion
}
Sounds like a serious bug in the service (or even the framework). Support for HEAD in HTTP/1.1 is in no way optional.
I have a WCF service with a client application. I have complete control over both the client and server implementation. I have hundreds of methods in the WCF contract which need a piece of information supplied by the client. Instead of modifying hundreds of methods, is there a way I can send specific data from the client with every call to the service, possibly somewhere in the channel?
Maybe when the client is setting up the proxy before making the call, it can store this data somewhere in an internal property of the proxy... the data would then get sent to the server and from within the service method I could inspect the OperationContext or some other piece of memory to get this data back and use it?
Any ideas?
It sounds like you are wanting something like headers like with SOAP webservices. I'm not a WCF expert, but this looks like the WCF equivalent.
It shouldn't actually be that hard. The best way I can think of is to write an IClientMessageInspector that adds a SOAP header into the Message.Headers in its BeforeSendRequest method.
See e.g. http://weblogs.asp.net/paolopia/archive/2007/08/23/writing-a-wcf-message-inspector.aspx
You can't do this trivially. It will take some work.
It's true that SOAP Headers are the perfect way to pass out-of-band data to and/or from a service. But you already have your contract defined, and adding headers will change the contract.
I believe you'll have to start using message contracts.
Original:
[DataContract]
public class ComplexObject
{
[DataMember(Name = "Id")]
public int Id;
[DataMember]
public string Name;
}
[ServiceContract()]
public interface IMyContract
{
void MyOperation(ComplexObject co);
}
public class MyService : IMyContract
{
#region Implementation of IMyContract
public void MyOperation(ComplexObject co)
{
// use co.*
}
#endregion
}
Using Message Contracts:
[DataContract]
public class ComplexObject
{
[DataMember(Name = "Id")]
public int Id;
[DataMember]
public string Name;
}
[DataContract]
public class MyHeader
{
[DataMember]
public string UserName;
[DataMember]
public string Password;
}
[DataContract]
public class OutputHeader
{
[DataMember]
public string Token;
}
[MessageContract]
public class MyOperationRequest
{
[MessageHeader]
public MyHeader Authentication;
[MessageBodyMember]
public ComplexObject TheObject;
}
[MessageContract]
public class MyOperationResponse
{
[MessageHeader]
public OutputHeader OutputHeader;
}
[ServiceContract()]
public interface IMyContract
{
MyOperationResponse MyOperation(MyOperationRequest request);
}
public class MyService : IMyContract
{
public MyOperationResponse MyOperation(MyOperationRequest request)
{
// use request.TheObject.*
// Can also read request.Authentication.*
return new MyOperationResponse
{ OutputHeader = new OutputHeader { Token = "someToken" } };
}
}