Substitute WCF Endpoint Address in VSTS Release Management - continuous-integration

I'm using VSTS to Build and Deploy a Windows Service to several different servers. Within the App.config for my Windows Service I have a reference to a WCF Service that I'm calling:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IMobileSyncService">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://192.111.11.111/1.0.0.18/MobileService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMobileService"
contract="MSSRef.IMobileService" name="WSHttpBinding_IMobileService" />
</client>
I'm currently using the same Build for all servers but using the Release Management stage of VSTS to substitute values in my App.config (for example, Connection Strings and server specific values). This is working perfectly.
With reference to the above code example however, how would I substitute the endpoint address out for values specific to each server? I'm not sure how to target this specific block in the config file.

There are some extensions that can do it, for example:
Release Management Utility tasks, related article: Using Tokenization (Token Replacement) for Builds/Releases in vNext/TFS 2015
Replace Tokens
You also can do it programming through PowerShell.

Related

Deploy Azure App Service with multiple Virtual Applications using Visual Studio 2022

I currently am using Azure Cloud Service (classic) and am able to effectively deploy a WebApp that contains 4 virtual applications using an Azure Cloud Service project. My ServiceDefinition.csdef file looks like:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="My.Azure.Web.API" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6">
<WebRole name="My.Web.API" vmsize="Small">
<Sites>
<Site name="Web" physicalDirectory="{path to My.Web.API}">
<VirtualApplication name="webapp1" physicalDirectory="{path to My.Web.WebApp1}" />
<VirtualApplication name="webapp2" physicalDirectory="{path to My.Web.WebApp2}" />
<VirtualApplication name="webapp3" physicalDirectory="{path to My.Web.WebApp3}" />
<VirtualApplication name="webapp4" physicalDirectory="{path to My.Web.WebApp4}" />
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
<Binding name="HttpsIn" endpointName="HttpsIn" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
<InputEndpoint name="HttpsIn" protocol="https" port="443" certificate="{certname}" />
</Endpoints>
<Imports>
<!--<Import moduleName="Diagnostics" />-->
<Import moduleName="RemoteAccess" />
<Import moduleName="RemoteForwarder" />
</Imports>
<ConfigurationSettings>
</ConfigurationSettings>
<Certificates>
<Certificate name="{certname}" storeLocation="LocalMachine" storeName="My" />
</Certificates>
</WebRole>
</ServiceDefinition>
I am working on migrating to Azure App Service and despite some significant digging I can not seem to find an equivalent/similar deployment process in Visual Studio for multiple Virtual Applications in Azure App Service.
I have found numerous posting that indicate using the publish function in the actual WebApp projects, but I would have to perform 4 separate deployments instead on one. And need to pre-define the virtual directories in the App Service configuration. Under the current approach, virtual applications/directories are defined during the deployment.
I plan to eventually move to Azure DevOps Pipelines for CI/CD and hope there is a mechanism to achieve this, but for now would just like something functional from Visual Studio.
Is there an equivalent/similar deployment process in Visual Studio for multiple Virtual Applications in Azure App Service? If not, what are the options?
Apologies if this a re-tread. I did my due diligence with no definitive answers. Unless of course the answer is right in front of me!?
Thanks for your time!
Eric
Check the below steps to deploy multiple Virtual Applications to Azure App Service from Visual Studio 2022.
Create a new App Service in Azure Portal.
In App Service Overview, click on the Download publish profile.
In VS 2022, create Applications of your desired framework. I have taken .NET Core Apps as an example.
Visual Studio Project Folder Structure
The option to create Virtual Directories in Azure Portal is available only for Azure Windows App Service.
In Azure Portal => App Service => Configuration => Path mappings => Under Virtual applications and directories create New Virtual application.
Make sure the Virtual Path is same as Web App Name in VisualStudio.
Publish each Application in VS to Azure App Service using the Downloaded Publish Profile.
Right click on the 1st WebApp Project => Publish => Add a publish profile => Import Profile.
Browse and upload the Publish Profile which we have downloaded from Azure Portal App Service.
Change the settings of the Application.
The site name must be the App Service name/VirtualPathName which we have created in portal.
Ex: Here it is VirtualApps29Dec/WebApp1.
Save and continue with next steps to publish the App.
Follow the same steps with the same Publish Profile for WebApp2, WebApp3 and WebApp4 as well.
Deployed Azure App Service Structure in KUDU Console
The Url's for the Applications will be
https://virtualapps29dec.azurewebsites.net/WebApp1
https://virtualapps29dec.azurewebsites.net/WebApp2
https://virtualapps29dec.azurewebsites.net/WebApp3
https://virtualapps29dec.azurewebsites.net/WebApp4
Initially When I tried to access the Applications, I got the below error.
When I check the Web.config of the deployed Applications, I can see the below code.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\WebApp2.dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" hostingModel="inprocess" />
</system.webServer>
</location>
</configuration>
<!--ProjectGuid: c238430b-40de-45d7-bbb7-ad96da7c4dc4-->
AspNetCoreModuleV2 will not allow multiple In-process virtual apps within the same app service plan.
I have resolved the issue by changing AspNetCoreModuleV2 to AspNetCoreModule
Edit all the Web.config files under the deployed Applications.
Output :

How to fix: "Metadata contains a reference that cannot be resolved:'http://<host>:<port><path>?wsdl'." for "Configure WCF Web Service Reference" in vs

I have been trying to publish a WCF web service on my IIS server using a nonstandard HTTPS port. Access to the server should only be possible after authentication (via basic authentication). The web service I created for testing purposes is the base project you get by default when creating a WCF Service Application in Visual Studio. The only modifications I made are in the web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="SoapApi.Service1">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="SoapApi.IService1"/>
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
After the service was published on the local file system and the IIS was configured. I was able to reach the WSDL file on the server after authentication from the browser on my local PC. But if I'm trying to add the service to a simple client application using the Configure WCF Web Service Reference wizard from Visual Studio, I get the following error message:
Metadata contains a reference that cannot be resolved:'http://<host>:<port><path>?wsdl'.
and the full error message:
An error occurred while attempting to find services at 'http://<host>:<port><path>?wsdl'. The remote server returned an error: (403) Forbidden.
Since this error indicates that I don't have access permission, I thought why not turn off authentication and try if it works. I activated anonymous access for the website in IIS and deactivated basic authentication.
Furthermore I changed the following passage in the web.config file:
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
I can still access the WSDL file from my browser, but nevertheless I still get the same error when adding the service reference to the client. The same happens if I test it via dotnet-svcutil http://<host>:<port><path>?wsdl
If I try to add the service reference locally everything works without any issues.
Additional information:
I already installed .NET Framework 4.6 and it's WCF HTTP Activation handler.
I added the permission IIS_IUSRS to the folder containing the service.
Any ideas to why this happens and what I could do to fix this problem?
If you use transport security mode, why not use https addresses? The https/http base address should be configured in IIS site binding module.
In addition, since you are using basic authentication, please turn on anonymous authentication and basic authentication in the IIS authentication module.
On my side, I can add service references correctly using the Core-based console application.
Besides, Please enable the following windows feature for WCF.
Feel free to let me know if there is anything I can help with.

App.Config for Federated Security with client certificate in Thinktecture IdentityServer

Currently I can establish a WCF channel with an IssuedToken by first establishing the security token from the STS with a certificate credential via the WS-Trust endpoint and then calling CreateChannelWithIssuedToken() on the channel factory. See How to specify a certificate as the credentials for a wsTrustChannel with Thinktecture IdentityServer
However, instead of doing this:
var securityToken = GetMeASecurityTokenFromTheSts();
var myServiceChannelFactory = new ChannelFactory<IMyService>();
myServiceChannelFactory.CreateChannelWithIssuedToken(securityToken);
I'd ideally like to just do this (and have the issuer of the security token automatically issue a token based on the passed certificate).
var myClient = new MyServiceClient();
My question is - can a binding be configured something like the following to specify that the ThinkTecture IdentityServer STS is the Issuer for security tokens?
<bindings>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding">
<security mode="TransportWithMessageCredential">
<message issuedKeyType="BearerKey" issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<issuer address="https://mymachine/myidserver/issue/wstrust/mixed/certificate">
<identity>
<certificateReference storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="XXXXXXXXXXXXXXXXXXXXXXXXX"/>
</identity>
</issuer>
<issuerMetadata address="https://mymachine/myidserver/FederationMetadata/2007-06/FederationMetadata.xml" />
<tokenRequestParameters>
<trust:SecondaryParameters xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:TokenType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</trust:TokenType>
<trust:KeyType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
<trust:Claims Dialect="http://schemas.xmlsoap.org/ws/2005/05/identity"
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<wsid:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
xmlns:wsid="http://schemas.xmlsoap.org/ws/2005/05/identity" />
</trust:Claims>
<trust:CanonicalizationAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
<trust:EncryptionAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
</trust:SecondaryParameters>
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
</bindings>
if so - I'm having a lot of trouble configuring this part of the binding:
<issuer address="https://mymachine/myidserver/issue/wstrust/mixed/certificate">
<identity>
<certificateReference storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="XXXXXXXXXXXXXXXXXXXXXXXXX"/>
</identity>
</issuer>
My main area of confusion is this: The issuer config element seems to encapsulate the binding, behavior and endpoint all in one element. The binding can be configured - and clearly has to as the above issuer element complains about not having a binding configured. But how do you specify the SSL certificate for the issuer channel as this is a behavior configuration thing, and there doesn't appear to be any way to set the behavior for the issuer endpoint.
Using the config only approach has indeed the problem of binding the token lifetime to the proxy lifetime. In addition the realm (appliesTo) you configure in IdentityServer has to match the physical URL of the WCF service. Both is IMO not practical and the "manual" WSTrustChannelFactory approach is much more recommended.
That said - svcutil (or "Add Service Reference") creates all the necessary client configuration for you. You just need to make sure that you point to IdentityServer's MEX endpoint in the WCF service configuration, e.g.:
<bindings>
<ws2007FederationHttpBinding>
<binding>
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false"
issuedKeyType="BearerKey">
<issuerMetadata address="https://identity.thinktecture.com/idsrvsample/issue/wstrust/mex" />
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
</bindings>
https://github.com/thinktecture/Thinktecture.IdentityServer.v2/blob/master/samples/MVC%20and%20WCF%20RP%20(SAML)/Web/Web.config
...and the MEF issue is fixed btw.
You can set binding configuration for issuer. Use of certificate will be set on MyServiceClient behaviour. I have not tested this configuration but it could work.
Here is your modified configuration
<bindings>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding">
<security mode="TransportWithMessageCredential">
<message issuedKeyType="BearerKey" issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<issuer address="https://mymachine/myidserver/issue/wstrust/mixed/certificate" binding="ws2007HttpBinding"
bindingConfiguration="issuerBindingConfig">
</issuer>
<issuerMetadata address="https://mymachine/myidserver/FederationMetadata/2007-06/FederationMetadata.xml" />
<tokenRequestParameters>
<trust:SecondaryParameters xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:TokenType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</trust:TokenType>
<trust:KeyType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
<trust:Claims Dialect="http://schemas.xmlsoap.org/ws/2005/05/identity"
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<wsid:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
xmlns:wsid="http://schemas.xmlsoap.org/ws/2005/05/identity" />
</trust:Claims>
<trust:CanonicalizationAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
<trust:EncryptionAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
</trust:SecondaryParameters>
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
<ws2007HttpBinding>
<!--SWACA RAWS Client authentication binding-->
<binding name="issuerBindingConfig">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" establishSecurityContext="false" />
</security>
</binding>
</ws2007HttpBinding>
</bindings>
<endpointBehaviors>
<behavior name="MyServiceClient">
<clientCredentials supportInteractive="false">
<clientCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="XXXXXXXXXXXXXXXXXXXXXXXXX" />
</clientCredentials>
</behavior>
</endpointBehaviors>
However please keep in mind that if you do that then each new MyServiceClient() will practically request a token from STS. When we used this approach in our system we had some MEF threadsafety problems with IdentityServer.

Silverlight and WCF with Windows Authentication

I have a Silverlight application in an ASP.NET web application. I then have a WCF Service Library hosted in an ASP.NET application. I have set up security as TransportWithCredentialOnly and Windows authentication. This is an Intranet scenario.
In IIS7 on a test server I have Anonymous Authentication disabled and Windows Authentication enabled. With this set up the WCF calls fail.
If I enable Anonymous Authentication then it works. What is the point of Windows Authentication if Anonymous Authentication cannot be disabled.
When I used Web Helper in IE it seemed that there was a call to the service similar to when you get the service definition and this need the Anonymous Authentication. I presume then that the actual calls to the Service methods will still be authenticated correctly.
Can anyone please shed some light on this as I am confused. We will be having penetration testers in a few months and I fear that they will not like the idea that they can see the service call in Fiddler or similar which they can then copy and paste into the address bar to get the service definition. Having worked with them before they are very particular and any information they can get from an app is a minus mark. In my particular industry security is extremely important.
If I am doing this wrong any help would be greatly appreciated.
I already struggled with the same problem. I fixed my problem by modifying my web.config file . Here is what I have below.
I hope that will help you!
Good luck.
<system.serviceModel>
<bindings>
<customBinding>
<binding name="MyAp.Web.Services.MyAppSvc.customBinding0">
<binaryMessageEncoding>
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" />
</binaryMessageEncoding>
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" authenticationScheme="Ntlm" unsafeConnectionNtlmAuthentication="true" />
</binding>
</customBinding>
</bindings>
<services>
<service name="MyApp.Web.Services.MyAppSvc">
<endpoint address="" binding="customBinding" bindingConfiguration="MyApp.Web.Services.MyAppSvc.customBinding0" contract="MyApp.Web.Services.MyAppSvc" />
<!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>-->
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>

Publishing a WCF Server and client and their endpoints

Imagine developing a WCF solution with two projects (WCF Service/ and web application as WCF Client). As long as I'm developing these two projects in visual studio and referencing service to client (Web Application) as server reference there is no problem. Visual studio automatically assign a port for WCF server and configure all needed configuration including Server And Client binging to something like this in server:
<service behaviorConfiguration="DefaultServiceBehavior"
name="MYWCFProject.MyService">
<endpoint address="" binding="wsHttpBinding" contract="MYWCFProject.IMyService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/MyService.svc" />
</baseAddresses>
</host>
</service>
and in client:
<client>
<endpoint address="http://localhost:8731/MyService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMyService"
contract="MyWCFProject.IMyService"
name="WSHttpBinding_IMyService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
The problem is I want to frequently publish this two project in two different servers as my production servers and Service url will be "http://mywcfdomain/MyService.svc". I don't want to change config file every time I publish my server project.
The question is: is there any feature in Visual Studio 2008 to automatically change the URLs or I have to define two different endpoints and I set them within my code (based on a parameter in my configuration for example Development/Published).
Check the answer i posted here for a similar question (how to set client endpoints programmatically).
The other way to do it and keep it totally declarative is to write an installer for your app, and have the installer update the config files. This solution would be a bit more pure, but harder to implement, and exactly how it is done would depend on which installer you use.

Resources