In my web application, I have a service reference (not web service reference).
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
public partial class LoginClient : ClientBase<Login.LoginClient>, Login.LoginSvc
{
public LoginClient() {
EndpointAddress address = new EndpointAddress(ConfigurationManager.AppSettings["login_svc"]);
this.Endpoint.Binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
this.Endpoint.Address = address;
}
}
Basically, I have the "login_svc" in the AppSettings. However, it throws the flowing exception:
I don't want to add the service configuration to the web.config system.servicemodel....instead I just want to use the appsettings for the url. How do I do this?
Rather than trying to do this in the constructor, you should just use one of the overloaded constructors already available to you when you instantiate the proxy in your client application. For example,
MyService.Service1Client proxy = new MyService.Service1Client(
new BasicHttpBinding(),
new EndpointAddress("<YOUR ENDPOINT ADDRESS>"));
Also, it's not recommended to edit the auto-generated code like this because if you update your service reference, then those changes will be lost because the Reference.cs file is regenerated at that time. Of course, you could copy the Reference.cs and make it a file in your project you manage as one of your own. It's not clear if you were doing that or not but just wanted to mention this just in case.
Related
I can't seem to find an example of generating proxies from WSDLs with shared types but without having any XSDs to go along with them. Can anyone please mark this as duplicate and point me to an example please?
Here are 2 services, each has its own namespace and a common type. The only thing that is publicly accessible are their WSDLs, there is no type's XSD or its .dll to pass to wsdl.exe /sharedtypes or svcutils and without it I end up with identical class Foo that I can't pass in to SetFoo and class Foo1.
The best I could come up with is generating proxies programmatically and detecting duplicates via CodeDOM, ignoring DataContract/WebServiceBinding namespaces, but it's a huge mess...
[WebService(Namespace = "http://tempuri.org/FOO1")]
public class Service1 : WebService
{
[WebMethod]
public Foo GetFoo()
{
return new Foo();
}
}
[WebService(Namespace = "http://tempuri.org/FOO2")]
public class Service2 : WebService
{
[WebMethod]
public void SetFoo(Foo foo)
{
}
}
public class Foo
{
public int Bar { get; set; }
}
There is a way of doing this, which is outlined here.
In your case you can skip the first step, generate the proxy from service 1 and then use the /r flag on svcutil to reference the service 1 proxy assembly when you generate your service 2 proxy.
This will ensure your service 2 proxy will use the same instance of Foo from your service 1 proxy.
However, have you considered just hosting a single service with two operations? It would save you a lot of work.
Edit: Also have a look at this post:
http://blogs.msdn.com/b/youssefm/archive/2009/10/09/reusing-types-in-referenced-assemblies-with-svcutil-s-r-switch.aspx
First off, you need to set the [DataContract(Namespace="some namespace here")] for all common service data types, otherwise when the WSDL and XSDs are generated then you will have objects from two difference namespace --- this is absolutely essential. The namespace value will only apply to the types defined in the XSD and not in the WSDL. XSD = data, WSDL = service.
The XSDs and WSDL and generated if, and only if, you have the META service behavior set - add this behavior and then you can navigate to the URL. The URL of the META service behavior will then have a link to your WSDLs and XSDs.
I use the following piece of code to self-host services in windows services rather than through IIS, however the same principals apply....
/// <summary>
/// Enables meta data output for a service host.
/// </summary>
/// <param name="host">The service host.</param>
/// <remarks>Must be invoked prior to starting the service host.</remarks>
public static void SetupMetaDataBehaviour(ServiceHost host)
{
ServiceMetadataBehavior metaDataBehaviour = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metaDataBehaviour == null)
{
metaDataBehaviour = new ServiceMetadataBehavior();
metaDataBehaviour.HttpGetEnabled = true;
host.Description.Behaviors.Add(metaDataBehaviour);
}
else
{
metaDataBehaviour.HttpGetEnabled = true;
}
}
after adding your two web references:
double click on the second web service reference
in the object browser navigate to the definition of Foo
right click on Foo and choose go to definition
delete the definition for the class Foo
add a using statement for the namespace of webservice one
find and replace all instances of <namespace-of-service-reference-2>.Foo with just Foo
This should fix your problem as it forces the autogenerated code for both service references to use the same class declaration.
I have a WCF Host with something like this:
[ServiceContract]
public interface IMountToOs
{
[OperationContract]
char GetMountDriveLetter();
[OperationContract]
MyTestClass MyTest();
}
public class MyTestClass
{
public string A { get; set; }
public string B { get; set; }
}
Client
private IMountToOs _proxy;
public IMountToOs Proxy
{
get
{
if (_proxy == null)
{
NetTcpBinding binding = new NetTcpBinding();
binding.MaxReceivedMessageSize = 2147483647;
binding.OpenTimeout = TimeSpan.FromMilliseconds(50000);
EndpointAddress address = new EndpointAddress("net.tcp://localhost:1234/MountToOsHost");
//_proxy = new MountToOsClient(binding, address);
ChannelFactory<IMountToOs> factory = new ChannelFactory<IMountToOs>(binding);
_proxy = factory.CreateChannel(address);
}
return _proxy;
}
}
While I can access
MessageBox.Show("Okay - " + Proxy.GetMountDriveLetter());
I can't call this method:
MessageBox.Show("Okay - " + Proxy.MyTest().A);
The complete extension is not working. But only while using it in an extension. Even if I insert a Messagebox in the first line of the extension it is not hit. I don't know why. It seems to run a pre-check and find the call of the custom class which is refused or so...
If I use a winform or so there is no problem.
.net 3.5
curious is that I have a break-point and a message of the hosts side. So I see that the method is not called
Update
now I moved the wcf-call in the Load Method of the extension and get a exception:
System.MissingMethodException: method not found:
"Contracts.Interfaces.MyTestClass
Contracts.Interfaces.IMountToOs.MyTest()".
My winform test and this extension use the same interface so that the method should known from both. no contract or so is outdated
According to what I found here and in the comments of the post: "For creating dynamic service proxy using client channel factory method, you will need datacontracts of the service. If you don't have datacontracts but you have the service URL, then you could use reflection to create proxy at runtime and call the service method."
Seems that the MyTestClass type is not known on the client side, so I think you could use reflection, or share the class between the client and server or much more simple, use the datacontract attribute.
Also, found something on MSDN that says something like this:
"When to use a proxy?
We create proxy using svcutil.exe. The output of this tool gives a proxy class and makes corresponding changes to the application configuration file. If you have a service that you know is going to be used by several applications or is generic enough to be used in several places, you'll want to continue using the generated proxy classes. We use proxy in WCF to be able to share the service contract and entities with the client. Proxies have several restrictions like they need to have gets and sets , contructors can't be exposed , methods other than the service contract cannot be exposed, repetition of code, everytime that we add/modify a service contract/data contract/message contract we need to re-generate the proxy for the client.
When to use ChannelFactory
The other option is using the ChannelFactory class to construct a channel between the client and the service without the need of a proxy . In some cases, you may have a service that is tightly bound to the client application. In such a case, it makes sense to reference the Interface DLL directly and use ChannelFactory to call your methods using that. One significant advantage of the ChannelFactory route is that it gives you access to methods that wouldn't otherwise be available if you used svcutil.exe..
When to use a ChannelFactory vs Proxy class?
A DLL is helpful if the client code is under you control and you'd like to share more than just the service contract with the client -- such as some utility methods associated with entities and make the client & the service code more tightly bound. If you know that your entities will not change much and the client code is less, then a DLL would work better than a proxy. If the client to your service is external to the system, such as API, it makes sense to use a proxy, because it makes sharing the contract easier by giving a code file rather than a DLL."
We cant see the class
MountToOsClient: IMountToOs
So we can only assume it is ok.
[DataContract] // Missing
public class MyTestClass
{
[DataMember] // Missing
public string A { get; set; }
[DataMember] // Missing
public string B { get; set; }
}
MountToOsClient can not expose Mytestclass without these attributes.
my application is composed by a lot of different windows service. Each of them creates programmatically a WCF service. I tried to configure my service with a "per-call" instancecontextmode but it seems to process one request at time.
What should I do?
The class implementing the service interface is decorated with this attribute:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
While the service is instantiated like this:
ServiceHost _host = new ServiceHost(typeof(IMultiMarketBatchNotification));
_host.AddServiceEndpoint(typeof(IMultiMarketBatchNotification), binding, myAddress);
where:
IMultiMarketBatchNotification is the service interface
binding is the instance of the binding (NetTcpBinding)
myAddress is a string containing the service url (like net.tcp://...)
Isn't that enough?
Thanks,
Marco
You need to add those lines of code after instating your ServiceHost, but before opening it:
// look for the "ServiceBehavior"
ServiceBehaviorAttribute srvBehavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
if (srvBehavior == null)
{
// if we didn't find the service behavior - create one and add it to the list of behaviors
srvBehavior = new ServiceBehaviorAttribute();
srvBehavior.InstanceContextMode == InstanceContextMode.PerCall;
host.Description.Behaviors.Add(srvBehavior);
}
else
{
// if we found it - make sure the InstanceContextMode is set up properly
srvBehavior.InstanceContextMode == InstanceContextMode.PerCall;
}
That should do it.
I have a WCF service XYZ that will be deployed on a number of hosts. Each such service may have a connection to another XYZ service deployed on one of the other hosts. It's a distributed system where the states will differ between the services.
In order to communicate it doesn't really make sense for me to "Add Service Reference" in Visual Studio because that will just add redundancy (the service already knows what it's going to be communicating with).
So currently my idea is to specify the other service endpoints in the App.config files of each service. For example:
<client>
<endpoint name="BEL"
address="tcp://us.test.com:7650/OrderManagementService"
binding="tcpBinding"
contract="IOrderManagementService"/>
<endpoint name="BEL2"
address="tcp://us.test2.com:7650/OrderManagementService"
binding="tcpBinding"
contract="IOrderManagementService"/>
</client>
Now, I just want a way to read these settings and create ChannelFactories and Channels in my code. However, it's turning out to be a hassle to do this.
Two questions: am I doing things right; and if so, what's the best way to extract these values from the config file?
Creating channels directly isn't hard, and all the endpoint configuration is read in for you. Try something like this:
var factory = new ChannelFactory<IOrderManagementService>("BEL");
var proxy = factory.CreateChannel();
// call methods on proxy
proxy.Close();
Note that the proxy needs closing properly (which means calling Close or Abort correctly) as soon as you have finished with it. However, you can leave the factory open for long periods, even in a cache.
You can encapsulate this into helper methods to make the calling code simple:
public static ChannelFactory<TContract> NewChannelFactory<TContract>(string endpointConfigurationName) where TContract : class {
// TODO: Cache the factory in here for better performance.
return new ChannelFactory<TContract>(endpointConfigurationName);
}
public static void Invoke<TContract>(ChannelFactory<TContract> factory, Action<TContract> action) where TContract : class {
var proxy = (IClientChannel) factory.CreateChannel();
bool success = false;
try {
action((TContract) proxy);
proxy.Close();
success = true;
} finally {
if(!success) {
proxy.Abort();
}
}
}
WebConfigurationManager can be used to get your Endpoints. You have a client section so in the GetSection just pass it through like the code above.
ClientSection clientSection = (WebConfigurationManager.GetSection("system.serviceModel/client") as ClientSection);
foreach(ChannelEndpointElement cee in clientSection.Endpoints)
{
// Store your endpoint for future use with ChannelFactories
}
If I understand your question correctly it's similar to something I wanted to do. I didn't want to include Service References in every library or app that needed access to the service. I created a Mediator pattern class that did have a service reference and served as a proxy to the service. It took an endpoint string as the only class constructor argument. The constructor looked like this (I threw in a channel factory example as a comment)
public DspServiceMediator( String serviceAddress)
{
EndpointAddress end_point = new EndpointAddress(serviceAddress);
NetTcpBinding new_tcp = new NetTcpBinding(SecurityMode.None);
new_tcp.ReceiveTimeout = TimeSpan.MaxValue;
new_tcp.SendTimeout = new TimeSpan(0, 0, 30); //30 seconds
//_channelFactory = new ChannelFactory<DspServiceClient>(new_tcp, end_point);
_dspClient = new DspServiceClient(new_tcp, end_point);
}
I actually replicated each property in the service (many times I had little mods that made the service easier to use by the final client) but you could just violate the law of Demeter in your client code and return the underlying service client (_dspClient in the code above) and use that.
Since all your connections are the same contract, and essentially the same client code, you can use the same ChannelFactory to create as many ServiceChannels as you need, and you can connect each ServiceChannel to different EndpointAddresses as specified in regular old application settings, or in a database:
private List<string> _endpointLists = new List<string>() { "127.0.0.0:1234" };
private static ChannelFactory<IWCFServiceChannel> _channelFactory = new ChannelFactory<ServiceReference.IWCFServiceChannel>("App.config Binding Name Here");
private List<WCFServiceChannel> _serviceChannels = new List<WCFServiceChannel>();
foreach (string uriEndpoint in _endpointLists)
_serviceChannels.Add(_channelFactory.CreateChannel(new EndpointAddress(uriEndpoint)));
_serviceChannels[0].Open();
...
And you can do this as many times as you need to, using the same ChannelFactory, but creating new ServiceChannels with different endpoints each time.
I created a WebService using the .NET 2.0 framework, a class based on an interface that has the WebServiceAttribute and hosting it using IIS and a ASMX file. The WebService currently loads its configuration from one XML file.
I'd like to create multiple instance of this service where each loads it own configuration.
By coping the ASMX file I can create a clone of the webservice under a different name which will be based on exact the same implementation. But it also loads the exact same configuration file which makes it rather useless.
So my question is: What is the best way to create an arbitrary number of WebServices that are based on one class, living in one IIS virtual directory where each is loading a different configuration file?
Solution
With the help of Pavel Chuchuva's answer I created the following code to handle the loading of the configuration:
public class WebConfigManager
{
public static T Load<T>() where T: new()
{
string location =
HttpContext.Current.Request.PhysicalPath + ".config";
if (HttpContext.Current.Cache[location] is T)
{
return (T)HttpContext.Current.Cache[location];
}
using (Stream s =
new FileStream(location, FileMode.Open, FileAccess.Read))
{
return (T)(HttpContext.Current.Cache[location] =
new XmlSerializer(typeof(T)).Deserialize(s));
}
}
}
// example of the usage of WebConfigManager
public class MyWebService : IMyWebService
{
Config config = WebConfigManager.Load<Config>();
...
Copy and paste .asmx file to create multiple instances of your web service (e.g. Service1.asmx, Service2.asmx and so on).
Load configuration file based on Context.Request.FilePath value:
public string LoadConfig()
{
string configPath = Server.MapPath(this.Context.Request.FilePath + ".xml");
using (XmlReader reader = XmlReader.Create(configPath))
{
// Will read Service1.asmx.xml, Service2.asmx.xml and so on
}
}
I suggest placing the asmx in different folders and placing a web.config in each of those folders with the setting for that specific instance of the web service. This is the easy and fast way
OR
you could use Web Service Enhancements 3.0 and create a WSE router, redirect a calls to a ASMX to that router and let the router forward the call to the right web service instance and pass additional config. This a more complex way of doing it but it enables u to use a single instance of the web service that's picks the right configuration based on the parameters the router passes it.
For more info on WSE3.0 I point you to the MSDN.
Hope this helps!