A little background:
I'm creating a set of adapters to allow communication with mobile devices over different cellular networks. This will be achieved using a class factory pattern. At least one of the networks requires a service reference to communicate with their devices through a web service.
So far I've got 3 assemblies so far which represent:
An assembly which contains the main adapter library: this contains
The interface definition for each of the adapters
Base classes
The class factory to instantiate the specified adapter at runtime.
An assembly for each network adapter implementation.
An assembly that contains my main application.
Given that I don't want to be adding service references and their configuration to the main application assembly [as that's not relevant to the main application], how do I force each assembly's service reference to get its configuration from its own app.config?
If I have the service reference configuration in the main app.config, everything works just fine, but if I move the configuration to the adapter's app.config everything stops working throwing the following exception at the point where I new up the Soap1Client.
"Could not find default endpoint element that references contract 'MobileService.Service1Soap' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element."
In the end, I just removed the service reference and added a web reference [i.e. did it the 2.0 way]. For some reason the web reference will access its own app.config instead of the main application's app.config.
Far easier than the alternative...
You can set all the options programatically.
I don't believe there is a built in .NET way to accomplish this. However you should be able to accomplish it by writing some code to parse each referenced assembly's .config file.
Here is a sample using assembly specific configuration files that should point you in the right direction: http://www.bearcanyon.com/dotnet/#AssemblySettings.
I've done something similar in a .NET Winforms app and it worked out well.
If you must have the library read the configuration for the service from a config file, then you might be out of luck. The library becomes part of the process and the process uses the configuration of the application that initiated the process.
However, in your library you could use one of the service reference proxy class constructor overloads to dynamically set the configuration when you instantiate the service reference. Then you don't have to have the service reference binding configuration in any config file. The overload I use takes two parameters: System.ServiceModel.Channels.Binding binding & System.ServiceModel.EndpointAddress remoteAddress. Note that the Binding class is a abstract class, you have to use one of the classes that inherit from it - you can find a list of them here: https://msdn.microsoft.com/en-us/library/system.servicemodel.channels.binding(v=vs.110).aspx.
For a simple http service reference I use a default instance of the BasicHttpBinding class and create an instance of the EndpointAddress class using the URL of the service I'm referencing. Obviously you would have to modify this to use https or secured services, etc.
Of course this still begs the question of how does the library get the correct service URL if you don't want to hard code it in the library? A couple of ways would be to read it from a database or a known file location.
Related
I'm attempting to architect a solution involving a WCF service, which calls a dll containing an EntityFramework6 model. When I attempt to unit test the service however, I receive a message:
Additional information: No connection string named 'SyslogEntities' could be found in the application config file.
My flow is arranged logically as:
SyslogDataSvcTest.dll (app.config has service bindings) ->
SyslogDataSvc.svc (web.config has provider and connection string) ->
LibSyslogData.dll (app.config has providers and connection string)
All the code that touches EF is in the libSyslogData.dll. It maps data to upper layer objects internally, and returns them, instead of exposing its own model info, so EF use should be really isolated.
So what am I doing wrong?
Edit:
I got it working well, but in perhaps a weird way. It seems the settings in my app.config were not correctly specified by NuGet when installing the EF and MySql dependencies.
Instead I created an in-code configuration class as described on MSDN here:
https://msdn.microsoft.com/en-us/data/jj680699
Now that I have this class:
public class EFConfiguration : DbConfiguration {
public EFConfiguration()
{
//For some reason this works much better than the app.config.
//With this defined, upper layer config documents need only specify the "SyslogEntities" Connection string.
SetExecutionStrategy("MySql.Data.MySqlClient", () => new MySqlExecutionStrategy());
SetDefaultConnectionFactory(new MySqlConnectionFactory());
SetProviderFactory("MySql.Data.MySqlClient", new MySqlClientFactory());
SetProviderServices("MySql.Data.MySqlClient", new MySqlProviderServices());
}
}
I can leave the specifics of the DB implementation to the datalayer, and only configure the connection string at the upper layers.
You most likely don't test the actual wcf service (I mean online) based on that exception. I think you are just unit testing the wcf service dlls code. So this would mean the app.config used is from the unit test assembly. Just 1 app.config for runtime for application, having an app.config for a class library does not make sense anyway either.
You need to provide the EF connectionstring that your EF data-access layer is using in your unit test assemblies, as you are doing in your wcf services web.config (since you are not testing the online wcf service). If you want to be totally free of EF references in your unit tests and wcf service configs, you need to override the default constructors for your EF entities and provide the "normal" dbprovider + connectionstring in your app/web configs and create the EF connection string(s) on the fly.
I currently have one Web Service in a solution of multiple projects. Since I don't want to add service references in all project to be able to use it, I have created a project with static a class named "ServiceHelper" for the moment. This project would be the only one with the service references and the helper would do all the request ncessary. The Web Service is set public (not internal).
My problem here is that when I initialize my SoapClient in my helper from another project that do not have the service references, it throws an exception. But when I add the service reference to that other project, it works. Is it normal or not?
The exception throwed translated (because it is said in French) is :
Unable to find an element endpoint default refers to the contract 'ServiceReference.WebServiceSoap' section in the ServiceModel client configuration. This may be due to the fact that the configuration file of your application is not found or the endpoint element matching this contract is found in the client element
Is there something missing in my config file? because I didn't change anything in the 2 projects mentionned.
Exemple of how I initialize my SoapClient in my helper :
private static ServiceReference.WebServiceSoapClient _webService = new ServiceReference.WebServiceSoapClient();
Following on with #zverev.eugene, you don't need the references in every project, but the web.config or app.config in the project is where the connection and configuration information is retrieved from. This is because the application calling your class library is what supplies all configuration information (e.g., if you have a data access layer in a class library, the connection string would come from the .config of the application calling the DAL, not the class library itself).
Environment :
Visual Studio 2010 Professional
.NET Framework 4
C#
Added Service Reference using the following WSDL : https://www.paypalobjects.com/wsdl/PayPalSvc.wsdl
Problem 1 : When compiled simply like this, get a bunch of errors from the Reference.cs file. Looks like namespace errors. It mentions that it cannot find the Service Reference Namespace in my project's Namespace. Therefore, I went into the Reference.cs file and whereever I got this error, I removed the project's namespace before the method names, and now it compiles.
Finally getting access to all classes.
Created and populated DoDirectPaymentReq and CustomSecurityHeader objects with the required properties.
Created an instance of PayPalAPIAAInterfaceClient class, which contains the method DoDirectPayment which takes in the arguments of type CustomSecurityHeader and DoDirectPaymentReq. Looks like this :
using (var client = new **PayPalAPIAAInterfaceClient**())
{
var credentials = new CustomSecurityHeaderType
{
Credentials = new UserIdPasswordType
{
Username = "xxxxxxxx#xxxxxx.com",
Password = "xxxxxxx",
Signature = "jksadfuhasfweakjhasf"
}
};
_doDirectPaymentResponseType = client.DoDirectPayment(ref credentials, _doDirectPaymentReq);
}
Problem 2 : After writing a TestMethod for the method which contains the above code, I get the error as follows :
System.InvalidOperationException: Could not find default endpoint element that references contract 'Paypal.PayPalAPIAAInterface' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.
at System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)
at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName, Configuration configuration)
at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)
at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)
at System.ServiceModel.ChannelFactory`1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress)
at System.ServiceModel.EndpointTrait`1.CreateSimplexFactory()
at System.ServiceModel.ClientBase`1.CreateChannelFactoryRef(EndpointTrait`1 endpointTrait)
at System.ServiceModel.ClientBase`1.InitializeChannelFactoryRef()
at System.ServiceModel.ClientBase`1..ctor()
at PaymentEngine.Paypal.PayPalAPIAAInterfaceClient..ctor() in Reference.cs: line 30063
Therefore, so far I have not been able to make a successful transaction using PayPal SOAP protocol via using WSDL in C#.
I was under the impression that this is very simple. Simply Add Service Reference and utilize the Classes with their properties and methods created in the proxy from WSDL.
Where am I going wrong ?
Am I using the wrong WSDL ? I'd like to test against Sandbox first and then go Live.
If I am right with the WSDL, looks like the class PayPalAPIAAInterfaceClient doesn't know its endpoint, which I don't know if I am suppose to set manually or not since its already there in the WSDL definition at the end (check it out). I think the class itself should know which endpoint to call depending on whether I am using Signature or Certificate to populate CustomSecurityHeaderType.
But how does the PayPalAPIAAInterfaceClient class know whether I am trying to call into the Sandbox (testing) or it is a live transaction ?
PayPal used to have two different WSDLs for Sandbox and for Live. They can be found here :
->https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_soap_PayPalSOAPAPIArchitecture
After speaking to their support I was asked to use the following WSDL for both Sandbox and Live:
->https://www.paypalobjects.com/wsdl/PayPalSvc.wsdl
But how do I tell the PayPalAPIAAInterfaceClient class when it is suppose to perform Live or Sandbox tests. And also to which end point to use depending on my method of SOAP and Signature. The endpoints from PayPal are mentioned here :
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/howto_api_endpoints
HELP !
You have a few problems here, but none should be too painful to resolve. First of all, when I add a Service Reference to the WSDL you link at the top of your post I don't have any of the problems with namespaces that you describe. It could be that your own namespaces/references are conflicting somehow with the auto-generated terms, or perhaps that you selected some strange option during the add reference process? A delete-and-re-add might solve the problem, or I guess you can just ignore it since you've already worked around it. (It is kind of a hassle to edit auto-generated code, however, so you should plan on a fix eventually.)
To resolve the InvalidOperationException, you probably just need to specify one of the endpoints that Visual Studio has automatically added to your app.config file. You should have something like this in your config file:
<system.serviceModel>
<client>
<endpoint name="PayPalAPI" ... />
<endpoint name="PayPalAPIAA" ... />
</client>
</system.serviceModel>
You can pass the name of the endpoint you want to the constructor of the proxy class. There are other options to solve this problem, but just specifying an endpoint is easy and clean. (Note: if you don't have this section in your config file, then something went wrong during the Add Service Reference phase. Again I would just suggest resetting your project and re-adding the reference.)
Finally, you don't want to use a using block when you make use of the proxy class in spite of it being IDisposable. Basically, there's a design bug in WCF.
I had the same problem, because I was doing unit testing.
You have to copy the application.config file to the test project, otherwise it won't find the WCF config.
Which one of this two ways of using wcf service is better? why?
Generating proxy from Service Reference
using ChannelFactory
ex.
ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>();
IMyContract proxy1 = factory.CreateChannel();
proxy1.MyMethod();
It is a bit boring to call wcf service like so
IMyContract proxy1 = null;
try
{
proxy1 = factory.CreateChannel();
proxy1.MyMethod();
((ICommunicationObject)proxy1).Close();
}
catch
{
((ICommunicationObject)proxy1).Abort();
}
Should we repeat this snippet for every proxy call? Or Is there generic way to create a wrapper class for closing and aborting proxies?
Is writing class like this ServiceExecution.Execute(proxy=>proxy.MyMethod()); which creates proxy, and closes or aborts it good way to do that?
Here is an MSDN post, that recomends not to use generated proxies in .Net 3 because it creates ChanelFactory each time, .Net 3.5 ChanelFactory is cached.
But personally I prefer to use ChanelFactory myself, generated code is always a pain even after partials come out
In first case when you use VS to add Service Reference it generates all the code for you including ServiceContrcats and DataContracts.
But when you use ChannelFactory you must have service contracts and etc on client side already.
I suggest using approach 1.
I've found this blog with an example including source code that also explains how to properly handle the connection (closing, aborting, etc.). The blog also contains links for more details at MSDN.
Manually creating the service proxies from a running service might be a good alternative. The tool svcutil is what Visual Studio uses under the hood when adding a service reference. Using this, you can generate the proxy class in a common location, and then link to it in each project you require, and also gain better control over your proxy classes.
For example, to generate a proxy for a service called TestService running locally on port 8000, you would run the following in the Visual Studio command prompt, generating a proxy class TestServiceProxy.cs in the proxies directory.
cd "C:\src\proxies"
svcutil /noLogo /out:TestServiceProxy http://localhost:8000/TestService
There are some other useful parameters for the tool, for example:
Add /n:*,WcfServices.TestService will specify a namespace for the proxy class.
Add /config:TestServiceProxy.config and svcutil will generate a sample configuration file for using TestService including endpoints, bindings etc.
Add /r:"Common.dll" and the proxy class emitted by svcutil will not have definitions for types used by the service, but defined in the assembly Common.dll.
Use svcutil /? for more information.
So I believe all you have to do with .NET 2.0 vanilla web services (not WCF) is the following:
1) Add your service reference. In my case I'm using the PayPal WSDL
2) Before you can use any proxy class, you must first create an instance of your service reference
3) Once you create an instance of your service reference, then just do [servicereference].ProxyClassName.Method or whatever you're trying to access from those classes
right?
Ok, so I tried that. I added a service reference and named it SandboxSoapAPI. So that's what you see under references in my C# project.
In code I tried this:
SandboxSoapApi reference = new SandboxSoapApi();
but it doesn't recognize SandboxSoapAPI. Am I doing something wrong? I just want to start calling class methods, etc. with PayPal and I can't seem to get this right.
And if I'm not incorrect, as of .NET 2.0+ it handles the low level sending of the actual request over Http for SOAP web service references?
SandboxSoapAPI is not the SOAP client proxy type name. It's a namespace.
To check this, in VS.NET tick 'show all files' and drill into the Web References, open up the Reference.cs file, you will see the SandboxSoapApi is a subnamespace (not your SOAP client proxy name!) in the project's root namespace.
So either use the fully qualified name:
SandboxSoapAPI.YourProxyType client = new SanboxSoapAPI.YourProxyType();
Or use using SandboxSoapAPI; in your code where you need the SOAP client.