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

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 :

Related

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.

Substitute WCF Endpoint Address in VSTS Release Management

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.

NLog not writing in Asp.Net Web Api App

I have been trying to implement NLog as a trace writer in an Asp.Net Web Api 2.2 app. This is my web.config:
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" throwExceptions="true" internalLogFile="c:\file.txt">
<targets>
<target name="logfile" xsi:type="File" fileName="${basedir}/Logs/log.txt"/>
<rules>
<logger name="*" minlevel="Info" writeTo="logfile"/>
</rules>
</targets>
During debugging this works fine if I am using IIS Express as the host, but If I set the project to use Local IIS it fails with a System.UnauthorizedAccessException. I am running VS 2013 as an administrator too.
You should check whether the user, which is configured in the Local IIS to be used to run the appdomain of your web application, have the sufficient access rights to write to the ${basedir}/Logs directory.
Please, ensure that you can run this code from your application:
File.WriteAllText(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs\test.txt"),
"Some content");
When you are able to do this, you'll also would be able to do the logging

Custom JwtSecurityTokenHandler not being invoked

I have a .NET MVC application that uses Azure Active Directory for Auth.
I'm trying to add a custom JWTSecurityTokenHandler to authenticate a console app that performs some basic GET requests against the app. However every request just gets redirected to the Azure AD login page instead of being passed to the JWT handler (my breakpoints and logging statements in the handler are not being hit). Any ideas?
Web.config:
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="https://localhost:44300/" />
</audienceUris>
<securityTokenHandlers>
<add type="QS.Admin.Infrastructure.MyJwtHandler, QS.Admin" />
<securityTokenHandlerConfiguration>
<certificateValidation certificateValidationMode="None" />
</securityTokenHandlerConfiguration>
</securityTokenHandlers>
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
<authority name="https://[myaccessdomain].accesscontrol.windows.net/">
<keys>
<add thumbprint="[thumbprint]" />
</keys>
<validIssuers>
<add name="https://[myaccessdomain].accesscontrol.windows.net/" />
</validIssuers>
</authority>
</issuerNameRegistry>
<!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
<certificateValidation certificateValidationMode="None" />
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler requireSsl="false" />
<wsFederation passiveRedirectEnabled="true" issuer="https://[myaccessdomain].accesscontrol.windows.net/v2/wsfederation" realm="https://localhost:44300/" requireHttps="false" />
</federationConfiguration>
</system.identityModel.services>
in addition to the above advice,
the jwtsecuritytokenhandlers responsibility is to validate a jwt and serve claims upstream. I don't see session management anywhere in your config, if that is missing, each call to the host will require obtaining a new token from ACS.
The settings in web.config look right.
Couple of things to check :
Make sure ACS is configured to issue JWT tokens for your realm.
If you plug in the JwtSecurityTokenHandler from MS - is it getting hit? This will help in isolating the issue to your custom handler versus settings in ACS or web.config.

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