Nuget package to insert project name in web.config - asp.net-mvc

I've created a Nuget package which inserts a key/value pair called ApplicationName in the web.config file with a default value of Application Name.
Is there a way to get the name of the .Net MVC project that a user would be installing the package into the value of the key/value in a human readable format? i.e. Incorrect: ApplicationName Correct: Application Name
If it's not possible to get the project name, I suppose using some sort of command line option could work?

After a few days of pondering, here is the solution I came up with.
Create a web.config transform file to add the key/value pair to the AppSettings section.
Create an install.ps1 file, that grabs the project name, parses it and injects the new value for AppplicationName in the web.config.
Here's my web.config.install.xdt file:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings xdt:Transform="InsertIfMissing">
<add key="ApplicationName" value="Application Name" xdt:Transform="InsertIfMissing" xdt:Locator="Match(key)" />
</appSettings>
</configuration>
Here's is my install.ps1 script:
# Runs every time a package is installed in a project
param($installPath, $toolsPath, $package, $project)
# $installPath is the path to the folder where the package is installed.
# $toolsPath is the path to the tools directory in the folder where the package is installed.
# $package is a reference to the package object.
# $project is a reference to the project the package was installed to.
$p = Get-Project
$project_readable_name = ($p.Name -creplace '([A-Z\W_]|\d+)(?<![a-z])',' $&').trim()
# Solution based on answer found on Stackoverflow: http://stackoverflow.com/questions/6901954/can-nuget-edit-a-config-file-or-only-add-to-it
$xml = New-Object xml
# Find the web.config
$config = $project.ProjectItems | where {$_.Name -eq "Web.config"}
if($config) {
# Find web.config's path on the file system
$localPath = $config.Properties | where {$_.Name -eq "LocalPath"}
# Load Web.config as XML
$xml.Load($localPath.Value)
# Select the ApplicationName node
$node = $xml.SelectSingleNode("configuration/appSettings/add[#key='ApplicationName']")
# Change the ApplicationName value
$node.SetAttribute("value", $project_readable_name)
# Save the Web.config file
$xml.Save($localPath.Value)
}
Hope this helps anyone else!

Related

Tomcat 8.5 context path not working correctly

I have an application with the name cat_tiger.war that gets deployed as localhost:8080/cat_tiger but I want to change the context path to localhost:8080/cat/lion/ instead. I've added the META-INF/context.xml file as
<?xml version="1.0" encoding="UTF-8"?>
<Context copyXML="true" docBase="cat_tiger" path="/cat/lion"/>
and the server.xml file to be
<Host name="localhost" appBase="webapps"
copyXML="true" deployXML="true"
unpackWARs="true" autoDeploy="true">
but it still deploys as localhost:8080/cat_tiger/
Any ideas as to what else needs to be changed?
EDIT:
[1] Tomcat 8.5.3
[2]
04-Sep-2018 13:50:41.830 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDescriptor Deployment of configuration descriptor [/opt/tomcat/conf/Catalina/localhost/cat_tiger.xml] has finished in [2,750] ms
...
...
04-Sep-2018 13:50:39.070 WARNING [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDescriptor A docBase [/opt/tomcat/webapps/cat_tiger] inside the host appBase has been specified, and will be ignored
[3] I'm deploying through Netbeans but will have to be deployed in a Docker container eventually.
I don't understand why you are having problems, but I've created the web project using NetBeans 8.2 (File > New Project... > Java Web > Web Application), and successfully changed the context, so perhaps if I give details of my project you can identify where there's a crucial difference.
1 cat_tiger\web\META-INF\context.xml
My file looks identical to yours:
<?xml version="1.0" encoding="UTF-8"?>
<Context copyXML="true" docBase="cat_tiger" path="/cat/lion"/>
[2] Run output
Select the project node, right click and select Run from the popup menu to run on Tomcat 8.5:
ant -f D:\\NB82\\cat_tiger -Dnb.internal.action.name=run -Ddirectory.deployment.supported=true -DforceRedeploy=false -Dnb.wait.for.caches=true -Dbrowser.context=D:\\NB82\\cat_tiger -Duser.properties.file=C:\\Users\\johndoe\\AppData\\Roaming\\NetBeans\\8.2\\build.properties run
init:
deps-module-jar:
deps-ear-jar:
deps-jar:
library-inclusion-in-archive:
library-inclusion-in-manifest:
compile:
compile-jsps:
In-place deployment at D:\NB82\cat_tiger\build\web
Deployment is in progress...
deploy?config=file%3A%2FC%3A%2FUsers%2Fjohndoe%2FAppData%2FLocal%2FTemp%2Fcontext7953615149857268018.xml&path=/cat/lion
OK - Deployed application at context path [/cat/lion]
Start is in progress...
start?path=/cat/lion
OK - Started application at context path [/cat/lion]
run-deploy:
Browsing: http://localhost:8080/cat/lion
run-display-browser:
run:
BUILD SUCCESSFUL (total time: 0 seconds)
Actually, you probably don't need to run the application to see the problem; just select Deploy instead of Run from the popup menu. This is the output I get from Deploy:
ant -f D:\\NB82\\cat_tiger -Dnb.internal.action.name=redeploy -Ddirectory.deployment.supported=true -DforceRedeploy=true -Dnb.wait.for.caches=true -Dbrowser.context=D:\\NB82\\cat_tiger -Duser.properties.file=C:\\Users\\johndoe\\AppData\\Roaming\\NetBeans\\8.2\\build.properties run-deploy
init:
deps-module-jar:
deps-ear-jar:
deps-jar:
library-inclusion-in-archive:
library-inclusion-in-manifest:
compile:
compile-jsps:
Undeploying ...
undeploy?path=/cat_tiger
OK - Undeployed application at context path [/cat_tiger]
In-place deployment at D:\NB82\cat_tiger\build\web
Deployment is in progress...
deploy?config=file%3A%2FC%3A%2FUsers%2Fjohndoe%2FAppData%2FLocal%2FTemp%2Fcontext5063723197082921373.xml&path=/cat/lion
OK - Deployed application at context path [/cat/lion]
Start is in progress...
start?path=/cat/lion
OK - Started application at context path [/cat/lion]
run-deploy:
BUILD SUCCESSFUL (total time: 0 seconds)
[3] Tomcat log
Here are the deployment details in the Tomcat log, where you can see that my deployment shows the context correctly, whereas yours does not:
05-Sep-2018 23:09:09.321 INFO [http-nio-8080-exec-6] org.apache.catalina.startup.HostConfig.deployDescriptor Deploying configuration descriptor [C:\apache-tomcat-8.5.20\conf\Catalina\localhost\cat#lion.xml]
05-Sep-2018 23:09:09.334 INFO [http-nio-8080-exec-6] org.apache.catalina.startup.HostConfig.deployDescriptor Deployment of configuration descriptor [C:\apache-tomcat-8.5.20\conf\Catalina\localhost\cat#lion.xml] has finished in [13] ms
05-Sep-2018 23:09:09.338 INFO [http-nio-8080-exec-5] org.apache.catalina.util.LifecycleBase.start The start() method was called on component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/cat/lion]] after start() had already been called. The second call will be ignored.
[4] C:\apache-tomcat-8.5.20\conf\Catalina\localhost\cat#lion.xml
This is the file Tomcat created when deploying the application:
<?xml version="1.0" encoding="UTF-8"?>
<Context copyXML="true" docBase="D:\NB82\cat_tiger\build\web" path="/cat/lion"/>
Note that docBase contains an absolute path.
[5] server.xml
Here's the entire content. I'm using Tomcat 8.5. Note that the <host> element is slightly different to yours, but when I added copyXML="true" deployXML="true" to the <host> element (so it looked like yours) everything continued to work fine:
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
<GlobalNamingResources>
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
</GlobalNamingResources>
<Service name="Catalina">
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" relaxedQueryChars="[]|{}^+\`"<>"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
<Engine defaultHost="localhost" name="Catalina">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log" suffix=".txt"/>
<Context docBase="C:\apache-tomcat-8.5.20\wtpwebapps\PlusServlet" path="/PlusServlet" reloadable="true" source="org.eclipse.jst.jee.server:PlusServlet"/>
</Host>
</Engine>
</Service>
</Server>
Updated 9/6/2018:
Ignore the answer given above! Even though it happened to work for my configuration, the approach is explicitly disallowed in the Tomcat documentation.
Specifically, path should not be specified within the <Context> of a context.xml file placed within the application's META-INF directory. From the path description in the Common Attributes section of the Tomcat 8.5 documentation for the Context Container:
This attribute must only be used when statically defining a Context in
server.xml. In all other circumstances, the path will be inferred from
the filenames used for either the .xml context file or the docBase.
Even when statically defining a Context in server.xml, this attribute
must not be set unless either the docBase is not located under the
Host's appBase or both deployOnStartup and autoDeploy are false. If
this rule is not followed, double deployment is likely to result.

Microsoft.TeamFoundation.VersionControl.Client.ItemNotMappedException even when the workspace exists and has a mapping

Using TFS 2015 update 2, an agent was installed in a machine, the agent creates its workspace:
Some custom MSBuild tasks developed InHouse were implemented in the build definition that will run on the agent. Those tasks perform some operations against the TFS server.
When the build definition is queued for a new build here is what I got:
In the build machine I proceed to run the following script, in order to verify the existence of the workspace :
# Script to find a Team Foundation workspace
param(
[string] $workspaceHint = $(get-location).Path
)
begin
{
# load the needed client dll's
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.VersionControl.Client")
# fetches a Workspace instance matching the WorkspaceInfo found in the cache file
function getWorkspaceFromWorkspaceInfo($wsInfo)
{
$tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($wsInfo.ServerUri.AbsoluteUri)
$vcs = $tfs.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$vcs.GetWorkspace($wsInfo)
# TODO: likely add some convenience properties/methods for easier scripting support
}
}
process
{
# is there only 1 workspace in our cache file? If so, use that one regardless of the hint
$workspaceInfos = [Microsoft.TeamFoundation.VersionControl.Client.Workstation]::Current.GetAllLocalWorkspaceInfo()
if ($workspaceInfos.Length -eq 1)
{
return getWorkspaceFromWorkspaceInfo($workspaceInfos[0])
}
if (test-path $workspaceHint)
{
# workspace hint is a local path, get potential matches based on path
$workspaceInfos = [Microsoft.TeamFoundation.VersionControl.Client.Workstation]::Current.GetLocalWorkspaceInfoRecursively($workspaceHint)
}
else
{
# workspace hint is NOT a local path, get potential matches based on name
$workspaceInfos = #($workspaceInfos | ?{ $_.name -match $workspaceHint })
}
if ($workspaceInfos.Length -gt 1)
{
throw 'More than one workspace matches the workspace hint "{0}": {1}' -f
$workspaceHint, [string]::join(', ', #($workspaceInfos | %{ $_.Name}))
}
elseif ($workspaceInfos.Length -eq 1)
{
return getWorkspaceFromWorkspaceInfo($workspaceInfos[0])
}
else
{
throw "Could not figure out a workspace based on hint $workspaceHint"
}
}
The script is not able to find any workspace.
Then, the TFS 2015 Power tools were installed with its powershell cmdlets in the machine and run the following script:
if ( (Get-PSSnapin -Name Microsoft.TeamFoundation.PowerShell -ErrorAction SilentlyContinue) -eq $null )
{
Add-PSSnapin -Name Microsoft.TeamFoundation.PowerShell
}
$ws = Get-TfsWorkspace -Path C:\t\1\s
$ws.Folders
Showing the workspace and the items mapped.
Queuing new builds, keep showing the same error.
The workspace is a public server one, and following some ancient post in msdn forums, I clean the TFS cache in the machine.
Any clue how to make the Microsoft.TeamFoundation.VersionControl.Client be able to recognize the workspace?
I fixed the ItemNotMappedException problem on my machine by running something like the following PowerShell script;
$localReference = "C:\Repository\Project\Project.sln"
$teamProjectCollection="http://tfsserver:8080/tfs/projectcollection"
$username = $env:UserName
Add-type -AssemblyName "Microsoft.TeamFoundation.Client, Version=12.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a"
Add-type -AssemblyName "Microsoft.TeamFoundation.Common, Version=12.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a"
Add-type -AssemblyName "Microsoft.TeamFoundation.VersionControl.Client, Version=12.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a"
Add-type -AssemblyName "Microsoft.TeamFoundation.VersionControl.Common, Version=12.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a"
$folder = [System.IO.Path]::GetDirectoryName($localReference);
Push-Location $folder;
$tfsTeamProjectCollection = New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection($teamProjectCollection)
$versioncontrolServer = $tfsTeamProjectCollection.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
[Microsoft.TeamFoundation.VersionControl.Client.Workstation]::Current.EnsureUpdateWorkspaceInfoCache($versionControlServer, $username);
$workspace = $versioncontrolServer.GetWorkspace($localReference)
echo $workspace
Pop-Location
You will need to change the initial variables to match your environment.
Hope it helps
Recently I ran into a similar issue where it was throwing the error saying "There is no working folder mapping for 'Mapped path'"
Tried using below command to get the workspace path.
tf workspaces /format:detailed /owner:UserName /collection:http://TFSurl:8080/tfs
Mapping seemed to be fine.
using Workstation.EnsureUpdateWorkspaceInfoCache worked with like a gem.
Use the following link for sample code:
How to call GetWorkspace in TFS properly?
Please add the Microsoft.TeamFoundation.Common assembly in your script and try again.
# load the needed client dll's
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Common")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.VersionControl.Client")

Changing endpoint in Web.config during deployment with a Azure Powershell script

I recently created a Powershell script that deploys my Web Application (ASP.NET MVC) to Azure. It works like it should, but I figured out that it would improve the script a lot by being able to change the endpoint in the Web.config file during deployment, i.e. the script prompts the user for the address. The Web.config section looks like this:
<system.serviceModel>
<client>
<endpoint address="http://localhost:10421/MyService" binding="binding" bindingConfiguration="foo" contract="bar" name="id" />
</client>
</system.serviceModel>
I would like to change the endpoint address with my script.
Use the Get-Content cmdlet to load your configuration file, access the property and change it and finally write it back using the Set-Content cmdlet:
[xml]$content = (Get-Content 'your_file')
$content.configuration.'system.serviceModel'.client.endpoint.address = 'YourNewAdress'
$content | Set-Content 'your_file'
Note: I asume that the system.serviceModel is within the configuration node. If not, omit that.

Is there a way to include 'Remote Controller name' in *.runsettings file?

I'm having a integrated environment with TFS BuildServer + TestControler + Several TestAgents.
Previously I used a *.testsettings file and define the remote server under Roles.
I update the BuildServer to VS2013 and introduced SpecRun for test executions.
As i'm having a custom *.srprofile file for TFS, I have to use a .runsettings file instead of .testsettings file.
I can not find a tag where i can define "Remote Controller name" in .runsettings file.
Is there a way to include 'Remote Controller name' in *.runsettings file??
I'm very new to Build Configurations. Any insight highly appreciated.
Additional Details:
I found this article and defined the .testsettings file path inside the .runsettings file. Following are the changed files according to the article.
But It's not working.
May be SpecRun Adaptor do not support tag.
TestSettings file i used.
<?xml version="1.0" encoding="UTF-8"?>
<TestSettings name=".........." id="........." xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>Remote settings for running the tests on.....</Description>
<Deployment>
....
</Deployment>
<RemoteController name=".....local:6901" />
<Execution location="Remote">
<TestTypeSpecific>
<UnitTestRunConfig testTypeId=".....">
<AssemblyResolution>
<TestDirectory useLoadContext="true" />
</AssemblyResolution>
</UnitTestRunConfig>
</TestTypeSpecific>
<AgentRule name=".....">
</AgentRule>
</Execution>
<Properties />
</TestSettings>
Sample *.runsettings file i'm using now.
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<!-- Configurations that affect the Test Framework -->
<RunConfiguration>
<!-- Path relative to solution directory -->
<ResultsDirectory>......</ResultsDirectory>
</RunConfiguration>
<SpecRun>
<Profile>TFS.srprofile</Profile>
<ReportFile>TestResults.html</ReportFile>
<GenerateSpecRunTrait>true</GenerateSpecRunTrait>
<GenerateFeatureTrait>false</GenerateFeatureTrait>
<SettingsFile>.....\Remote.AutoTest_2013.testsettings</SettingsFile>
<ForcedLegacyMode>true</ForcedLegacyMode>
</SpecRun>
</RunSettings>
OK, I think the mistake you've made is to use the runsettings file. You specify it in the testsettings file instead. Ours looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<TestSettings name="RemoteTest" id="9cfa5873-0238-4d56-a1ec-079192fa72c8" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>Settings set up to run remotely through test controller</Description>
<RemoteController name="**YOURCONTROLLERMACHINE**" />
<Execution location="Remote" hostProcessPlatform="MSIL">
<TestTypeSpecific>
<UnitTestRunConfig testTypeId="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b">
<AssemblyResolution>
<TestDirectory useLoadContext="true" />
</AssemblyResolution>
</UnitTestRunConfig>
</TestTypeSpecific>
<AgentRule name="AllAgentsDefaultRole">
</AgentRule>
</Execution>
<Properties />
</TestSettings>
You then call this from the command line, passing in the testsettings path:
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe" "C:\blahblah\TestsAssembly.dll" /Logger:trx /settings:C:\DummyTests\Remote.testsettings /Platform:x64
Where TestsAssembly.dll contains the tests you want to run, and Remote.testsettings is as above. The resultant .trx file appears in \TestResults...
You shouldn't need the runsettings file at all.

tomcat7 virtual directory mapping

I have followed this blog: A programmer's blog. All upload images go to
Z:\glass_server_upload and I added a file named ImageView#img.xml in the tomcat C:\Program Files\Apache Software Foundation\Tomcat 7.0\conf\Catalina\localhost. And the file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="Z:/glass_server_upload" reloadable="true" crossContext="true" path="/ImageView/img" debug="9"></Context>
And now I want to display the images, so I enter the browser like this: localhost:8080/ImageView/img/pulpit.jpg.
But the result is sadly 404.
According to the post the file should be
<Context docBase="Z:/glass_server_upload">
</Context>
What do you need to do:
Locate $CATALINA_BASE/conf/Catalina/localhost
Create a textfile there named ImageView#img.xml with the contents above
Start/restart Tomcat
Enter in the browser via http://localhost:8080/ImageView/img/yourimage.jpg
if the file exists and you have permission to read the file, then it will be shown.

Resources