Visual Studio - Adding two web references - c#

I'm using VS2012 and have successfully added a service reference to a web service, lets call it Web Service A. I can connect and interact with that webservice, it all works ok.
There's another version of the webservice (Web Service B) that I need to connect to, it's essentially the same but one is used for live and the other for testing. The URLs are different so I thought I could add a second reference without an issue.
However, when I do add Web Service B everything appears to work fine (web.config is modified etc.) but all my existing code that interacts with Web service A breaks, visual studio acts like it doesn't know what classes I'm trying to instantiate.
Can I have two very similar web references (different URLs) that I can easily switch between by changing the code? I would have thought I could but maybe not?

When you add a Service or Web Reference, along with all the code that VS create, the important bit is this thing in the web.config (or App.Config):
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="TempConvertSoap" />
</basicHttpBinding>
<customBinding>
<binding name="TempConvertSoap12">
<textMessageEncoding messageVersion="Soap12" />
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://www.w3schools.com/webservices/tempconvert.asmx"
binding="basicHttpBinding" bindingConfiguration="TempConvertSoap"
contract="ServiceReferenceA.TempConvertSoap" name="TempConvertSoap" />
<endpoint address="http://www.w3schools.com/webservices/tempconvert.asmx"
binding="customBinding" bindingConfiguration="TempConvertSoap12"
contract="ServiceReferenceA.TempConvertSoap" name="TempConvertSoap12" />
</client>
</system.serviceModel>
The example is from the Temperature Convesion service in w3schools.
In your scenario, you only need to add a single web reference and then, to connect to the other one, change this section, in particular the endpoint -> address attribute; as long as the webservice are IDENTICAL, it will work without problems.
As a bonus, being part of the web.config or app.config, you could use config tranforms to replace this with the proper address when building your Release.

If one is for live and another for test, I would add web.config transformations and then run your code under a 'test' configuration.
More info on web.config transforms here:
http://msdn.microsoft.com/en-us/library/dd465326(v=vs.110).aspx

Related

WCF / EF / SQL Server / VS2017 / C# : multi-tier application gets error when deployed to local IIS 10.0 as hosting server

I am trying to deploy a Windows desktop application with service layer, logic layer and data layer. The data layer uses SQL Server with EF 6.2. The UI client layer is a Windows Forms application.
The application works great in test debug mode when the service is hosted by the WcfSvcUtil.exe application with a service alias in IIS - no errors and all data retrieval and updates are working in test.
Now, I have published the Service layer, logic layer and data layer as an empty web site to be hosted by IIS on my local machine (c:/inetpub/wwwroot/) in the "alias" subfolder. I created an IIS application named with the alias name for the service. The UI layer and Service layer are published to a different local folder on my machine.
When I start the UI layer, and try to query the SQL Server database, I get the following error:
There was no endpoint listening at http://localhost/TheACTSFactoryWCFLocal/MemberService/ that could accept the message. This is often caused by an incorrect address or SOAP action. See innerException, if present, for more details.
My Service Model element in the web.config in the hosted web site is:
<system.serviceModel>
<services>
<service name="ACTSFactoryService.MemberService">
<endpoint name="BasicHttpBinding_IMemberService"
address=""
binding="basicHttpBinding"
contract="ACTSFactoryService.IMemberService" >
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/TheACTSFactoryWCFLocal/MemberService/" />
</baseAddresses>
</host>
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<serviceActivations>
<add factory="System.ServiceModel.Activation.ServiceHostFactory"
relativeAddress="./MemberService.svc"
service="ACTSFactoryService.MemberService" />
</serviceActivations>
</serviceHostingEnvironment>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMemberService"
maxReceivedMessageSize="20000000" maxBufferSize="20000000" />
</basicHttpBinding>
</bindings>
</system.serviceModel>
I'm new to WCF and Entity Framework so any suggestions would be appreciated. I also have an app.config and web.config in the Service layer, and app.config in the UI layer. I can post those if you think they will be helpful, but for the IIS web.config shown, I basically combined the endpoints from the Service layer's config files to be published to the IIS web site.
** Changed my web.config file as below **
***
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
</system.web>
<system.serviceModel >
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" >
<serviceActivations >
<add factory ="System.ServiceModel.Activation.ServiceHostFactory"
relativeAddress="./MemberService.svc"
service="ACTSFactoryService.MemberService" />
</serviceActivations>
</serviceHostingEnvironment>
<behaviors >
<serviceBehaviors >
<behavior >
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
***
Also, when I browse to http://localhost/TheACTSFactoryWCFLocal/MemberService.svc, my Service is found.
The following s the App.config in UI layer:
***
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMemberService" maxBufferSize="20000000"
maxReceivedMessageSize="20000000" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/TheACTSFactoryWCFLocal/MemberService/"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMemberService"
contract="MemberServiceProxy.IMemberService" />
</client>
</system.serviceModel>
</configuration>
***
Here is the IIS server folder named as the Alias name of the IIS app, there is not SVC file
Here are the DLL's, etc, published to the Bin folder
Does the IIS Server's Alias/Bin folder deployment look normal for a WCF service hosted in IIS 10.0 in .NET 4.5.2? Also, I did not publish anything to the Roslyn folder (CodeDom). Any comments or suggestions?
According to your description, I found that when you publish the service to IIS, the host tag still exists in your configuration file. Only self hosted or hosted programs like windows service need to configure host. When you host the service in IIS, the base address of the service is composed of the port number deployed in IIS and the file name of the service.
This is the configuration file of WCF service deployed in IIS.
I set the port number of the service to 8063.
Access this address and we will see the directory of the service.
Click service1.scv to see that the service starts normally.At this time, "localhost:8063/Service1.svc" in the address bar is the address of the service. The client needs to access this address to succeed.
update
If your project is deployed in IIS, I suggest using WCF service application template when creating a project.
The structure directory after the creation is like this:
Service1 is the implementation class of a service.
I could not get the IIS-hosted solution to deploy, so I changed my strategy to using a Self-Hosting Windows Forms project as the hosting application.
I changed my Service project from a VS2017 .NET4.5.2 WCF Service Library template to a WCF Service Application template, and was more successful in getting my total solution to work in development/debug mode.
However, I was not able to publish/deploy my solution properly to have IIS host the Service. So, I changed to using a Windows Forms "self-hosting" method instead. This suits my ultimate goal of being able to use Windows Forms controls, and it will work well for the intended users group for now.
Here is what I did:
Changed my Service project to WCF Service Application template.
In .NET 4.5.2, the *.SVC file is not required, but Interface and Implementation are.
Removed IIS Host Solution folder, added Windows Forms project as Service Hosting app.
Copied Service' Web.config to HostWinFormsApp project, renamed it App.config.
Made changes to the Hosting project's App.config to have
"serviceHostingEnvironment" section
Added "serviceActivations" section to it, pointing to base address in Hosting project
Like this: relativeAddress="./HostWinFormsApp/MemberService.svc"
Added almost the same to Web.config in Service project, but with the simple
relativeAddress="./MemberService.svc" only
With HostWinFormsApp and the Service app's configuration files corrected, I was able
start the Service, run SVCUTIL.exe and create my Service Proxy for the UI. This
utility also updated the UI Client's app.config with the Endpoint address:
<endpoint address="http://localhost:port#/HostWinFormsApp/MemberService.svc"
Added ServiceHost object to the HostWinFormsApp.Program.cs Main() function to host and start
the WCF Service "ACTSFactoryWCFServiceApp.MemberService".
Added System.Diagnostic.Process to UI client's Program.cs Main() function to launch
the hosting application, HostWinFormsApp, before "running" the UI Client's winform
(Form1).
With configuration files corrected, the new HostWinFormsApp project in place
with a ServiceHost object defined and the UI Client project starting the
HostWinFormsApp, I was ready to test.
Set the HostWinFormsApp and UI Client to both be startup projects, and ctrl-F5
to test. Both winforms started, Hosting project first, then client.
Changed Startup project to UI Client only, and Ctrl-F5. Both winforms started,
hosting first and client second. Client requested and received data in the ADGView
control.
In UI Client, Service and HostWinFormsApp projects' Properties page "Build events -
Post-build" option, added command to copy DLL files from bin\debug up one level
to .\bin folder. Cleaned and re-built Solution. (copy .\*.* ..\*.*)
Right-clicked on the Service project, published to target folder. publishing-folder\bin was
created including all DLL's from Service project copied to .\bin. Service's
Web.config was copied to publishing-folder.
Published HostWinFormsApp project, as StartUpProject, to same pub-folder. Setup.exe,
HostWinFormsApp.application and the subfolder "Application" were created in pub-folder.
Host project's DLL's were copied to "Application"
folder.
Renamed "setup.exe" to "Host.exe" and Ran as Administrator to complete setup.
Published ACTSFactoryUI (Windows Forms) client project to pub-folder as StartUpProject. Setup.exe,
ACTSFactoryUI.application were created, and ACTSFactoryUI project DLL's went into the "Application" folder.
Renamed "Setup.exe" to "Client.exe" and double-clicked to complete setup.
Created a "RunApps.bat" file to start both apps. Created a desktop Shortcut to the c:\pub-folder\RunApps.bat, edited "Advanced" in Shortcut to Run As Administrator.
Double-Clicked the Shortcut and Host.exe and Client.exe launched.
Screenshot below shows Service, UI Client, deployment folder and "Shortcut" icon on desktop.
The next pic shows the hosting WinForms project's Program.cs class. In this class, the
ServiceHost object is defined, with the Service type and the base address of the
Service, and then the Service Host is opened - which starts the Service running
(listening) for requests.
Once this (localdb) deployment was completed, I had to remove and reload my EntityFramework and rebuild the entity model class in the DAL layer using the Remote database as my source. Once the new connection & Entity Model for the remote database was completed, and all config files updated with new connectionString, I redeployed in same manner as above to my laptop - with the locally installed Service accessing the Remote database now. This was an EF DB Model First implementation. SQL Server database was built in MS SSMS.

C# - How to set service reference configuration in a third party application

I am currently implementing a plugin for a third party application in C#. The plugin is a library (DLL) and it calls some Web services. So, I created a Service Reference in Visual Studio, which is configured in the app.config file of the plugin as such:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="AuthenticationEndpointImplServiceSoapBinding" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8080/services/auth"
binding="basicHttpBinding" bindingConfiguration="AuthenticationEndpointImplServiceSoapBinding"
contract="AuthenticationWebService.AuthenticationEndpoint"
name="AuthenticationEndpointImplPort" />
</client>
</system.serviceModel>
</configuration>
I have another project, that I use for testing the plugin. When I call the service from that project, it works fine, provided I have copied the same configuration to this project's app.config file also. But when I build the plugin and run it from within the third party application, I get the following message:
Could not find default endpoint element that references contract
'AuthenticationWebService.AuthenticationEndpoint' 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.
I suspect the reason for the error is the fact that there is no configuration file for the third party application. Do you have any ideas how to work around this?
You could set up your parameters(binding, endpoint, etc.) explicitly in your plugin code after reading them from ordinary text file...
Here you will find some example:
https://msdn.microsoft.com/en-us/library/ms731862(v=vs.110).aspx

Could not find default endpoint element that references contract

I have a ASP .NET MVC app that I want to be able to connect to SOAP API.
I have created a wrapper project were I have my common methods that are working with the API. I have created this wrapper because the file generated by tool is so huge the project build would take ages.
From api doc site:
The tool then generates a single file named EconomicWebService.cs with the proxy code. This file can then be included directly in a project (this can slow down your Visual Studio as it is a rather big file) or built into a dll that can be referenced from your project)
I have referenced this wrapper as dll in my class library (middle layer) that is referenced into my MVC application.
Sadly it is not working, and I am getting this error:
Could not find default endpoint element that references contract 'S2s.Economic.WebService.EconomicWebServiceSoap' 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.
Webconfig
<system.web>
.....
</system.web>
<runtime>
...
</runtime>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="EconomicWebServiceSoap">
<security mode="Transport" />
</binding>
<binding name="EconomicWebServiceSoap1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://api.e-conomic.com/secure/api1/economicwebservice.asmx"
binding="basicHttpBinding" bindingConfiguration="EconomicWebServiceSoap"
contract="PTS.S2s.Economic.WebService.EconomicWebServiceSoap"
name="EconomicWebServiceSoap" />
</client>
</system.serviceModel>
</configuration>
I have managed to find a workarround with manual endpoint setup in the code.
EndpointAddress endpoint = new EndpointAddress( "https://api.e-conomic.com/secure/api1/economicwebservice.asmx" );

WCF service returning 404 on method requests

I have a WCF service page running only WebGets/WebInvokes over SSL - it works fine on my local machine (self signed cert). On production, however, I can reach service.svc (and it gives me the message about how to consume) but service.svc/AnyRequest returns a 404. Both environments are hosted in IIS 7.5.
I've enabled tracing and the service isn't even picking up any of the method requests (e.g. service.svc/SomeRequest), however it is processing service.svc just fine. It's also listening at https://computername.domain.net/path/service.svc - is this normal? Should it normally be pointing to https://publicfacing.com/path/service.svc?
Also note that the production server is hosting multiple sites within IIS.
Below is the system.serviceModel section of my web.config. The SSLBehave was suggested from here.
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SSLBehave">
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="https" port="443"/>
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="UserManagement.ajaxAspNetAjaxBehavior">
<webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="UserManagement.ajax" behaviorConfiguration="SSLBehave">
<endpoint address="" behaviorConfiguration="UserManagement.ajaxAspNetAjaxBehavior"
binding="webHttpBinding" bindingConfiguration="TransportSecurity" contract="UserManagement.ajax" />
</service>
</services>
</system.serviceModel>
The first thing I do whenever I hit a 404 with a newly-developed WCF Web Service is checking the handler mapping required to interpret this type of call, because it's often the cause of the issue. There are several ways to work around the problem, many of which require a manual execution of the ServiceModelReg.exe console command: these are undoubtedly valid procedures but might also not work – or create additional problems – if your development machine has a particularly complex configuration. The resolution method I propose below is slightly longer to pull off, but has the advantage of solving the problem more safely and securely.
Open the Server Manager interface for machine management, usually present in both the Task Bar and the Start menu.
Go to the Dashboard (or Control Panel) and select Add Role or Feature to open the Wizard.
Select the Role-based or Feature-based installation type and the server you want to work on, that is, your local / local server.
Go to the Features section: Once there, expand the .NET Framework 3.5 Features node and / or the .NET Framework 4.5 Features node, depending on what you have installed: if you have both, you should perform the following step twice (for each one of them).
Expand the WCF Services section (if available), then select HTTP Activation (see screenshot below).
Continue until you complete the Wizard, then click Install.
Once the installation is complete, you should be able to run your WCF Service without incurring in the 404 error ever again.
For additional info regarding this specific issue and how to fix it, you can also read this post on my blog.
I would start by checking a number of things;
Permissions on the hosted directory?
.Net version is correct?
Have you added the certificate to the site?
Try putting an image in the same path, can you navigate to that (rule out the odd occasional path mappings)
Good luck!
You can implement transport level security using WsHttp bindings. See this article; in your bindings try this biding instead:
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
The article mentions you should tie up the bindings with the end points.
I had the same problem. From what I read, WCF isnt NT Authenticated authorization (or HTTPContext compatible) by default.
I had to add this to my config file for the WCF service web.config in the section:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
Which you did, plus this:
And on the actual service class definiation I had to add:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DataService : IDataDeliveryServiceContract
This fixed my problem.
Perhaps in your RouteConfig.cs file add this line:
routes.IgnoreRoute("{resource}.svc/{*pathInfo}");
So long as your .svc file is in the root of the application.
As you mentioned you can access your service by .svc extension service.svc but not in REST format service.svc/AnyRequest, the problem must be in routing integration.
add this to your web.config
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
<handlers>
<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd"/>
</handlers>
</system.webServer>
In the IIS 6 The cause of this error must be Check that file exists setting of svc extention, make sure "Check that file exists is unchecked". For more information see IIS Hosted Service Fails.
To help others that find themselves stuck with this - It may be that your service name is not the fully qualified name, which it must be.
The following setting in web.config fixed a WCF .svc 404 on a HTTPS web site :
<webHttpBinding>
<!-- https -->
<security mode="Transport">
<transport clientCredentialType = "None" proxyCredentialType="None"/>
</security>
</binding>
</webHttpBinding>
I tried the above solutions, installing WCF Services, ensuring that there were proper permissions in the API directory and several other things.
While some of those were issues there was one issue for me that isn't mentioned above.
If Request Filtering is enabled for the entire server or the given site, make sure that .svc is a trusted file name extension, otherwise it will be blocked. Go to IIS > Request Filtering. Click on Edit Feature Settings. Check to see if "allow unlisted file extensions" is checked. If so, make sure that there is an entry in the list for .svc. Otherwise IIS will block the file from being served.

Changing WCF Service reference URL based on environment

I have a web application that uses a number of WCF Services. I deploy my web application in various environments (dev, UAT, production etc). The URL of each WCF Service is different for each environment. I am using .NET 3.5 andbasicHttpBindings
The web application uses a framework to support machine-specific settings in my web.config file. When instantiating an instance of a WCF Service client I call a function that creates the instance of the WCF Service client using the constructor overload that takes the arguments:
System.ServiceModel.Channels.Binding binding,
System.ServiceModel.EndpointAddress remoteAddress
In essence the <system.serviceModel><bindings><basicHttpBinding><binding> configuration in web.config has been replicated in C# code.
This approach works well.
However, I now have to enhance this approach to work with a WCF service that uses an X509 certificate. This means that I have to replicate the following additional settings in web.config in C# code:
<!-- inside the binding section -->
<security mode="Message">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
<behaviors>
<endpointBehaviors>
<behavior name="MyServiceBehaviour">
<clientCredentials>
<clientCertificate storeLocation="LocalMachine" storeName="My"
x509FindType="FindByThumbprint" findValue="1234abcd" />
<serviceCertificate>
<defaultCertificate storeLocation="LocalMachine" storeName="My"
x509FindType="FindByThumbprint" findValue="5678efgh" />
<authentication trustedStoreLocation="LocalMachine"
certificateValidationMode="None" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
I am having some difficulty figuring out how to code this configuration in C#.
Two questions
Can anyone recommend a better approach for managing WCF Service reference URLs across multiple environments?
Alternatively, any suggestions on how to replicate the above web.config section in C# will be welcomed
One possible approach would be to "externalize" certain parts of your <system.serviceModel> configuration into external files, one per environment.
E.g. we have "bindings.dev.config" and "bindings.test.config", which we then reference in our main web.config like this:
<system.serviceModel>
<bindings configSource="bindings.dev.config" />
</system.serviceModel>
That way, all you need to change from DEV to PROD is this one line of config XML.
Basically, in .NET 2.0 config, any configuration element can be "externalized". You cannot however externalize configGroups (such as "system.serviceModel") directly - you have to be on the "configuration element" level.
Marc
EDIT: OK, so NO config edit changes to switch between environments.....
In that case, you probably have to dream up a naming scheme, e.g. name your bindings, behaviors and endpoints in such a way, that you can distinguish them at runtime.
Something like:
<bindings>
<binding name="Default_DEV">
.....
</binding>
<binding name="Default_PROD">
.....
</binding>
</bindings>
that way, you could build up the name of the element you want (e.g. binding "Default_PROD") from your code and the environment you're running in, and then grab the according config from the config file which contains all the config settings for all environments.
The following code replicates the configuration in my original question:
myClient.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint,
"1234abcd");
myClient.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint,
"5678efgh");
myClient.ClientCredentials.ServiceCertificate.Authentication.TrustedStoreLocation = StoreLocation.LocalMachine;
myClient.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
In the production code the two thumbprint values are stored in appSettings in the web.config file.
We don't use web.config files at all, we specify everything programmatically and load all configuration from a centralized database.

Categories