Is there a way to create an instance of a WCF service client in C# with a specified endpoint address without specifying a configuration name?
By default, clients have these constructors:
public ServiceClient()
public ServiceClient(string endpointConfigurationName)
public ServiceClient(string endpointConfigurationName, string remoteAddress)
Obviously, there is a default configuration, because of the first constructor. What I want is to only specify the 2nd parameter of the final constructor. Right now, I'm struggling through reading the configuration elements of using ConfigurationManager to figure it out, but it seems horribly cumbersome. Is there a cleaner way?
I prefer not to use the endpoint configuration in the .config file. I normally do something like this:
BasicHttpBinding basicbinding = new BasicHttpBinding();
basicbinding.SendTimeout = TIMEOUT;
basicbinding.OpenTimeout = TIMEOUT;
ServiceClient client = new ServiceClient(basicbinding, new EndpointAddress(new Uri("http://xxxxx")));
Your generated client should also have a constructor that looks like this:
public ServiceClient(
System.ServiceModel.Channels.Binding binding,
System.ServiceModel.EndpointAddress remoteAddress)
: base(binding, remoteAddress) {
}
You can call this one without an endpoint configuration.
If you want to actually just want to call a service without having to know everything there is to know about WCF services and configuration handling, in C # you can just do...
String url = "http:\\somehost:someport\\pathToSomeService";
EndpointAddress address = new EndpointAddress(url);
Binding binding = new BasicHttpBinding();
YourClient client = new YourClient(binding, address);
// Call your client methods
client.SomeMethod(parm1, parm2);
The above assumes you generated a service reference and does not require configuration information to exist anywhere, not in the generated service reference, not in the DLL and not in the executable. No configuration. None.
I use the above in a true standalone service proxy dll. It is standalone in the truest sense of the word as it is completely configurable with no dependence on the calling executable to provide anything.
Well, you could use the default constructor, but then you'd have to manually program in all of the configuration settings. By specifying the configuration name, the service client will automatically load the configuration in from the .config file, all you need to know is which configuration to use (you can have multiple, e.g. one for HTTP and another for Net.Tcp). The remoteAddress, of course, just tells WCF where to make the connection.
If you are having trouble configuring the client settings themselves, make sure you're using the WCF Service Configuration tool. It works for both the service config as well as the client config.
Related
I am developing a single-tenant web application that will be deployed in client data centers and for security reasons we would like to disable the metadata exchange on the applications WCF services. Is it possible to do this this programatically within our service application or another mechanism besides the web.config? We want to prevent more technically minded clients from going to the web.config and turning metadata exchange back on.
You can disable the metadata exchange programmatically by setting the HttpGetEnabled/HttpsGetEnabled to false.
First, Create a derive host from ServiceHost.
public class DerivedHost : ServiceHost
{
public DerivedHost( Type t, params Uri baseAddresses ) :
base( t, baseAddresses )
{
DisableMetadataExchange();
}
private void DisableMetadataExchange()
{
var metadata = Description.Behaviors.Find<ServiceMetadataBehavior>();
if metadata != null)
{
// This code will disable metadata exchange
metadata .HttpGetEnabled = false;
metadata .HttpsGetEnabled = false;
}
}
}
Second, Create a derived factory from ServiceHostFactory.
public class DerivedFactory : ServiceHostFactory
{
public override ServiceHost CreateServiceHost( Type t, Uri[] baseAddresses )
{
return new DerivedHost( t, baseAddresses );
}
}
Third, Create or Edit your your svc file Markup and apply your derived factory.
<% #ServiceHost Factory=”DerivedFactory” Service=”MyService” %>
Fourth, Test your service in the browser and you should see a message contain "Metadata publishing for this service is currently disabled".
If want more details about this implementation kindly visit this link.
Yes. If you code your WCF service as "self describing", which basically means using a WCF intercept layer to handle all the incoming requests to an endpoint, you can just return null from the MEX request.
To make this work is a bit tricky but in my experience leads to a much cleaner implementation than all those voluminous web.config entries. This is described here WCF Configuration without a config file.
We have a WCF client application that talks to a series of different service endpoints that all expose the same contract (basically, proxy services for disparate backends). Because we don't know the endpoint URLs until run-time, we're creating the service proxy classes dynamically like this:
public Factory()
{
this.ProxyFactory = new ChannelFactory<IProxyServiceChannel>(new BasicHttpBinding());
}
public IProxyServiceChannel GetProxy(Uri uri)
{
return this.ProxyFactory.CreateChannel(new EndpointAddress(uri));
}
This works fine, except in certain cases where the proxy is sending data that's larger than the default maximum received side of 64k. Normally, we'd just go into the configuration file and change the basic HTTP binding to allow bigger messages. With WCF 4.0 and up, we usually do this on the default (unnamed) binding, like so:
<basicHttpBinding>
<binding maxReceivedMessageSize="2147483647"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<readerQuotas maxArrayLength="2147483647" />
</binding>
</basicHttpBinding>
Changing the default binding settings like this works for any services that we host in our application, as well as any service proxies that are created via "New Service Reference...". But for some reason, the new BasicHttpBinding() object we're supplying to our channel factory is not picking up these settings, and is falling back to the built-in defaults.
I had assumed that these binding settings would apply to any endpoint using a BasicHttpBinding that didn't have a more specific binding configuration specified. Is that correct? And if not, is there a way to get WCF to pick up these defaults automatically?
(NOTE: I know I can specify a name for the binding and use that in code, which is the option I'm currently pursuing, but for various technical reasons I'd prefer not to have to do that.)
new BasicHttpBinding() will give you an instance of BasicHttpBinding with the default values - I don't think it will read anything from the config file (even a default configuration) unless a configuration section name is passed in (which doesn't help for a default binding defined in the config file). What you want to do is create the instance and pass that in to the ChannelFactory. Something like this:
BasicHttpBinding binding = new BasicHttpBinding();
binding.MaxReceivedMessageSize = Int32.Max;
binding.SendTimeOut = new Timespan();
binding.ReceiveTimeout = new TimeSpan();
XmlDictionaryReaderQuotas quotas = new XmlDictionaryReaderQuotas();
quotas.MaxArrayLength = Int32.Max;
binding.ReaderQuotas = quotas;
this.ProxyFactory = new ChannelFactory<IProxyServiceChannel>(binding);
You could refactor the above so that you could generate via code any number of binding configurations (i.e., one method per binding configuration, for example).
I have a WCF RESTful service that I want to integration test so need to create an instance of the service locally within the test with a reference to a client channel that I can call. I can do this, however the code I'm using will only call the Services default parameterless constructor as below
_serviceHost = new WebServiceHost(typeof(UserService), baseAddress);
var binding = new WebHttpBinding();
_serviceHost.AddServiceEndpoint(typeof(Interface.IUserService), binding, address.Uri);
_serviceHost.Open();
In my UserService class, I want to inject a dependency into it for the data repository, as so
public UserService(IUserDataRepository userRepository)
{
_userRepository = userRepository;
}
How can I adapt the first lot of code so that I can create and self host my WCF REST service with an IDataRepository object that I create (Mock) in the test class?
Well, I think you can use the same approach as you have for production environment. I might be wrong but you must already have your custom ServiceHost and ServiceHostFactory. If not please take a look at this article Using Instance Provider and ServiceHostFactory to Construct the Service. You want to read through steps steps 1-3. You will need to derive from WebServiceHost to implement your own one. Then your code will look like that:
_serviceHost = new YourCustomServiceHost(typeof(UserService), baseAddress);
Hope it helps!
I like the WCF 4.0 capabality to host a service without an .svc file by setting a serviceActivations in the config file. It work great using the default service factory but now I'm trying to do the same using the AutofaServiceHostFactory so my dependencies will be properly injected. In all scenarios I tried, I still got this error when I try to access to service : The service 'WCFAutofacWiring.MyService' configured for WCF is not registered with the Autofac container. I host my service in an empty asp.net web site. Here's what I did :
Web.config :
<serviceHostingEnvironment>
<serviceActivations>
<add factory="Autofac.Integration.Wcf.AutofacServiceHostFactory"
relativeAddress="~/WASCurrentTime.svc"
service="WCFAutofacWiring.MyService" />
</serviceActivations>
</serviceHostingEnvironment>
Then, I put a file in the app_code folder to register my dependency as stated in the Autofac documentation (Autofac WcfIntegration) and I confirmed with the debugger that the code is called at service start :
public static class AppStart
{
public static void AppInitialize()
{
AutofacHostFactory.Container = new AutofacBootstrapper().Configure();
}
}
Finally, here's my registrations :
public class AutofacBootstrapper
{
public IContainer Configure()
{
var builder = new ContainerBuilder();
// register types
builder.Register<ILanguageProvider>(x => new MyLanguageProvider("en-US"));
builder.RegisterType<MyService>();
return builder.Build();
}
}
My service works perfectly if a use an .svc file instead of serviceActivation but I find it wasteful to create an .svc file if the only reason is to setup a factory that I can specify in my web.config.
Any idea ?
Thanks
According to the Autofac source, the exception is thrown if either a keyed resolution with the given string (from config) or a typed resolution using Type.GetType for the given string fails.
In your case the Type.GetType method probably returns null because you haven't specified a Type.AssemblyQualifiedName in the config.
Try getting typeof(MyService).AssemblyQualifiedName and insert that into the config.
Need a way for one service on a well-known Endpoint to return strings which are relative addresses. The client can then connect to Endpoints using these relative addresses.
Clearly this resembles REST in some ways, but in this case running a Windows Service using NetNamedPipeBinding for IPC, so no need for HTTP.
Don't want to create the Endpoint ahead of time since there will be a potentially large number of relative addresses, only some of which the client would be interested in.
All Contracts are known in advance.
Tried to find a solution with AddressFilterMode but wasn't sure how to provision new Binding so that client connected to it, UriTemplate but don't want to use the HTTP framework. Haven't looked into RoutingService because constrained to .Net 3.5.
Pseudocode for client would be something like that below...
namespace Testing
{
class RunTest
{
static void Test()
{
NetNamedPipeBinding namedpipe = new NetNamedPipeBinding();
ChannelFactory<Contracts.IRoot> factoryRoot =
new ChannelFactory<Contracts.IRoot>(
namedpipe
, new EndpointAddress("net.pipe://localhost/root");
);
Contracts.IRoot root = factoryRoot.CreateChannel();
ICommunicationObject commsRoot = root as ICommunicationObject;
commsRoot.Open();
// Service examines address and creates Endpoint dynamically.
string address = root.SomeFunctionWhichGetsARelativeAddress();
// IBar service routes endpoint requests internally based on
// "address" variable.
ChannelFactory<Contracts.IBar> factoryBar =
new ChannelFactory<Contracts.IBar>(
namedpipe
, new EndpointAddress("net.pipe://localhost/root/IBar/" +
address)
);
Contracts.IBar bar = factoryBar.CreateChannel();
bar.DoSomething();
}
} // Ends class RunTest
} // Ends namespace Testing
Message Filters are the way to go. You can use “Prefix” or create a custom.
WCF Addressing In Depth
From the Message Filters section of the article:
...it uses message filters to determine the matching endpoint, if one
exists. You can choose which message filter to use or you can provide
your own. This flexibility allows you to break free from the
traditional dispatching model when using Windows Communication
Foundation to implement things other than traditional SOAP—for
instance, the techniques described here enable you to implement
REST/POX-style services on the Windows Communication Foundation
messaging foundation.
Nice question, by the way. I learned something trying to figure this out.
AddressFilterMode.Prefix might suffice. The actual Endpoint used can be inspected in Service methods via
OperationContext.Current.IncomingMessageHeaders.To
Helper code can parse the endpoint and do any necessary internal processing from there.
Hopefully there's some extensibility on the server side which can simplify that code.
Pseudocode for host:
namespace Services
{
[System.ServiceModel.ServiceBehavior(AddressFilterMode =
System.ServiceModel.AddressFilterMode.Prefix)]
class BarService : Contracts.IBar
{
#region IBar Members
public void DoSomething()
{
System.Uri endpoint = System.ServiceModel.OperationContext.Current.IncomingMessageHeaders.To;
Console.WriteLine("DoSomething endpoint: {0}", endpoint);
}
} // Ends class BarService
} // Ends namespace Services
class RunHost
{
static void HostIBar()
{
System.Uri uriBase = new System.Uri("net.pipe://localhost");
System.ServiceModel.ServiceHost hostBar =
new System.ServiceModel.ServiceHost(
typeof(Services.BarService),
uriBase);
hostBar.AddServiceEndpoint(
typeof(Contracts.IBar) // Type implementedContract
, namedpipeBinding // System.ServiceModel.Channels.Binding binding
, "root/IBar" //string address
);
hostBar.Open();
Console.WriteLine("Press <ENTER> to stop...");
Console.ReadLine();
}
}
Correction: I'd originally said that this wouldn't treat "net.pipe://localhost/root/IBar/1" and "net.pipe://localhost/root/IBar/2" as distinct endpoints, but it does. Each causes its own WCF Service instance to be created and called.
An additional change was to encode the data in URL style query parameters and not embed it in the path. E.g.: "net.pipe://localhost/root/IBar?something=1&somethingelse=11" and "net.pipe://localhost/root/IBar?something=2&somethingelse=22" using HttpUtility.ParseQueryString