WCF service not working after program update - wcf

I have recently added a WCF service reference to my program. When I perform a clean install of this program, everything seems to work as expected. But, when I install the program on a client which already has a previous version (without the new service reference) installed, I get a exception telling me the default endpoint for this particular service could not be found.
It seems that the appname.exe.config is not being updated with the new endpoint settings. Is there any reason for this and how can I force the installer to overwrite the config file? I'm using the default Visual Studio 2008 installer project with RemovePreviousVersions set to True.
Update:
My program encrypts the settings section after the first run with the following code
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection section = config.GetSection(sectionKey);
if (section != null)
{
if (!section.SectionInformation.IsProtected)
{
if (!section.ElementInformation.IsLocked)
{
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
}
}
}
When I do not run the program before installing the new version the app.config gets updated.

You are right that it is the config file that is not updated.
There are several possibilities:
The installer has the old version of the config file
The installer does not have a config file and the program is using the old one on the machine
Try uninstalling the project first, then install and check that the config file has been copied in.

Related

Can't start ASP.NET Core 6 app running as Windows Service

I have created a simple, stripped down project to try to get this to work: ASP.NET Core 6 WebAPI project, hosted as a Windows Service, just trying to get it up and running with the sample WeatherForecast controller. I have added NuGet package for Microsoft.Extensions.Hosting (6.0.1) and Microsoft.Extensions.Hosting.WindowsServices (6.0.0). My program.cs looks like:
using IRDSPrototype.Configuration;
using IRDSPrototype.Services;
using Microsoft.Extensions.Hosting.WindowsServices;
var webApplicationOptions = new WebApplicationOptions
{
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService() ? AppContext.BaseDirectory : default
};
var builder = WebApplication.CreateBuilder(webApplicationOptions);
builder.Services.AddHostedService<IRDSHostingService>();
builder.Host.UseWindowsService();
builder.WebHost.UseUrls(UriServices.GetBaseUri().AbsoluteUri);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
await app.RunAsync();
I created a background service as well:
public class IRDSHostingService : BackgroundService
{
public ILogger Logger { get; }
public IRDSHostingService(ILoggerFactory loggerFactory)
{
Logger = loggerFactory.CreateLogger<IRDSHostingService>();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Logger.LogInformation("IRDS Hosting Service is starting.");
stoppingToken.Register(() => Logger.LogInformation("IRDS Hosting Service is stopping."));
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
Logger.LogInformation("IRDS Hosting Service has stopped.");
}
}
I also created a service installer via Wix. When I run the installer it gets to the point of "Starting services" and fails with a message 'Verify that you have sufficient privileges to start system services'. When I check Windows Application Log, I see that error and a also see an error for:
Application: IRDSPrototype.exe
CoreCLR Version: 6.0.822.36306
.NET Version: 6.0.8
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException: Could not load file or assembly 'System.ServiceProcess.ServiceController, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
File name: 'System.ServiceProcess.ServiceController, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
My publish directory and Wix manifest do include the System.ServiceProcess.ServiceController.dll.
I installed the service via sc.exe and the install succeeded, but starting the service gives an Error 5: Access Denied message. Unlike with the installer, though, this didn't generate any messages in the Windows log. I checked permissions on the folder containing the executable, giving full permissions to NETWORK SERVICE and LOCAL SERVICE. That didn't help. So I'm kind of stuck on what to do now. All my internet searches basically guided me to the setup I have now and it still doesn't work. So I'm at a loss. Anyone have any suggestions of what I'm missing here?
Thanks,
Dennis
Edit: So I'm whittling down the problem. It turns out I needed the version of System.ServiceProcess.ServiceController.dll that was published to my 'runtimes' folder under the .Net 6.0.0 runtime. So that error no longer shows up in the Event Viewer. The only erro that shows in the Event Viewer now is:
Error 1920. Service 'IRDS Prototype' (IRDSPrototype) failed to start. Verify that you have sufficient privileges to start system services
I have it installing as a Local Service and I believe I've given Local Service full permissions on the proper folders but I will check that. Still looking for suggestions though.
Edit #2: Getting closer. The problem I had when installing through sc.exe was that my binPath was wrong. I wasn't including the exe file in the binPath. Now I can install my service through sc.exe and it starts and works properly. The service still won't start when installed via my Wix installer though. So now I'm down to a Wix issue. Anyone with experience installing Windows services via Wix?
OK, it turns out what I needed to do was publish as a single executable:
Notice the "Deployment Mode: Self-contained" choice and "Produce single file" checked. After publishing that way, I only had to add the executable (no other files) to my Wix manifest and the generated installer worked fine. I'm guessing I was missing a dependency somewhere that I didn't know about. But it's weird that I was able to install and start the service from the same publish directory as I was trying previously with Wix via sc.exe. Anyway, it works now. Thanks to Md Farid Uddin Kiron for redirecting me back to the official page, which I read a little more carefully this time and found the little blurb about this being recommended.

Set Environment=Development when xunit testing an ASP.NET Core app

I xUnit test my ASP.NET Core web app, and my test class includes:
this.host = Program.CreateHostBuilder(Array.Empty<string>()).Build();
in order to access host.Services.
I discover that the host has Environment=Production. So the configuration seen in my startup file ignores appsettings.Development.json.
How do I inject or force host to have Environment=Development?
Preferably without any code in the web app itself.
(Context: I'm using JetBrains Rider. I find nothing in Rider setup or configuration that lets me choose an Environment for a UnitTest session. But if there is a solution on that line the question still stands)
I had assumed—wrongly—that I might fix it with this:
this.host = Program.CreateHostBuilder(
"ASPNETCORE_ENVIRONMENT=Development"
).Build();
because the docs say
The default configuration loads environment variables and command line arguments prefixed with DOTNET_ and ASPNETCORE_
but what fixed it was:
this.host = Program.CreateHostBuilder(
"ENVIRONMENT=Development"
).Build();
With this, the Configuration element then picked up the appsettings.Development.json file instead of ignoring it.
( So now I wonder whether part of the env variable processing is done by the dotnet executable before reaching Program.Main() )

SpaTemplate angular - Publish to Azure - Error: Cannot find module 'aspnet-webpack'

I use the asp.net core angular spatemplate. The project is running without problems on my local machine. However, when I publish it to azure I run into an internal server error.
After setting the aspnetcore_environment to development in the azure portal, I can see a the error:
Exception: Call to Node module failed with error: Webpack dev middleware failed because of an error while loading 'aspnet-webpack'. Error was: Error: Cannot find module 'aspnet-webpack'
I found some hints here https://github.com/sgbj/generator-aspnetcore-angular2/issues/23
Basically it says the node_modules folder is missing in the production environment. And it describes a way to add it manually to the project.json file. But the spatemplate didn't create such a file... it contains a classic *.proj
I am very new to web development and I don't know how to add the missing dependency to the proj file. And I am not sure if this is really the issue, because the sample I am following on the web https://channel9.msdn.com/events/Visual-Studio/Visual-Studio-2017-Launch/WEB-103 is not setting anything in this direction.
If I create a plain new project with
dotnet new angular
and I publish it everything works fine without any issues?! So I have the feeling I destroyed something in the solution?! Any idea?
My question is how can I set the node_modules for publishing?
In Startup.cs you probably have the below in Configure() method:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions {
HotModuleReplacement = true
});
}
This enables hot module replacement with webpack. When you make a change and save a file, webpack automatically re compiles the angular app so your browser picks up the changes without you reloading the page. You don't want this functionality when publishing.
"env.IsDevelopment()" will check for an environment variable on your PC = ASPNETCORE_ENVIRONMENT=Development
In the app service, add an app setting like below:
Alternatively you could comment the hot module replacement out.
Finally I found a solution for this problem. I removed the Publish Profile in my VS2017 solution and to delete the related app service on Azure. After creating everything new again the publishing works well again. I hope this will never ever happen in production.

Self-update / shadow-copy with Asp.Net Core

I'm writing a Asp.Net Core application which should be able to update itself (replace its own binaries while running).
This MSDN article describes shadow copying with the classical .Net framework, which would be exactly what I need. But the whole AppDomain thing is missing in .Net Core.
So my questions are:
Is there an alternative way in .Net Core to enable shadow copying the assemblies?
Are there other mechanisms in .Net Core that allow to build a self-updating application?
Since there is no built in mechanism in .NET Core for doing this, I ended up implementing my own custom solution. It works roughly like this:
The running application downloads and extracts new binaries to a new folder.
The running application starts a small updater process. The following parameters are passed to the updater process via command line:
Process id of the running application
Binary path of the running application
Path of the downloaded binaries
The running application exits itself.
The updater process waits until the running application has exited (using the process id) or forcefully kills the running application if it doesn't exit by itself within a given timeout.
The updater process deletes the existing binaries and copies the new downloaded binaries over.
The updater process starts the new version of the main application.
Make sure you do as much as possible in the main application (downloading, unpacking, validation, ...) and keep the updater process as simple as possible (minimize risk of failing).
This approach has proven to be quite stable.
There's no build in shadow copying facilities in .NET Core
.Net API Browser indicates that the property required to set this up in .Net Core is but AppDomainSetup is not.
To be clear, AppDomain was added in .Net Standard 2.0 but creating a domain is not currently Supported
To save someone having to do what I just did and make this - this only copies files with a different date modified time. I checked and rebuilding your app only changes this on a few files. This makes for a very fast self-loader that then starts the exe in the new location, and exits the exe doing the loading that was running from the old location. This may rely on a few things like your DLL running the code must be named the same as the EXE that starts it.
Works in .Net 5:
using System;
using System.Diagnostics;
using System.IO;
namespace NetworkHelper
{
public static class LocalCopier
{
public static void EnsureRunningLocally(string callingAssemblyDotLocation)
{
var assemblyFileFriendlyName = Path.GetFileName(callingAssemblyDotLocation.Replace(".", "-"));
var assemblyDirToCheck = Path.GetDirectoryName(callingAssemblyDotLocation);
var localLocation = Configuration.Tools.AppsLocation + assemblyFileFriendlyName + "\\";
var assemblyFinalExePath = localLocation + assemblyFileFriendlyName.Replace("-dll", ".exe");
// Check what assembly passed in path starts with
var runningFromNetwork = callingAssemblyDotLocation.ToLower().StartsWith(#"\\w2k3nas1\");
if (callingAssemblyDotLocation.ToLower().StartsWith(#"i:\")) runningFromNetwork = true;
if (!runningFromNetwork) return;
// Check if copied to local already
Directory.CreateDirectory(localLocation);
// Foreach file in source dir, recursively
CopyOnlyDifferentFiles(assemblyDirToCheck, localLocation);
Process.Start(assemblyFinalExePath);
Environment.Exit(0);
}
private static void CopyOnlyDifferentFiles(string sourceFolderPath, string destinationFolderPath)
{
string[] originalFiles = Directory.GetFiles(sourceFolderPath, "*", SearchOption.AllDirectories);
Array.ForEach(originalFiles, (originalFileLocation) =>
{
FileInfo originalFile = new FileInfo(originalFileLocation);
FileInfo destFile = new FileInfo(originalFileLocation.Replace(sourceFolderPath, destinationFolderPath));
if (destFile.Exists)
{
if (originalFile.LastWriteTime != destFile.LastWriteTime)
{
originalFile.CopyTo(destFile.FullName, true);
}
}
else
{
Directory.CreateDirectory(destFile.DirectoryName);
originalFile.CopyTo(destFile.FullName, false);
}
});
}
}
}
Note that "\w2k3nas1" and "i:" are examples of network locations where if it is running from those, it should copy itself to a local directory, I use application data/roaming/localApps and then restart itself from the new directory.
This can all be put into a reference library and be called from any client apps with:
NetworkHelpers.LocalCopier.EnsureRunningLocally(Assembly.GetExecutingAssembly().Location);
(Here, Assembly.GetExecutingAssembly().Location is passed in from the calling app, because if you were to run that from in the reference project, you'd get that library's dll instead.)
I made my own solution with PowerShell Core (available on Windows/Linux/Mac).
You can use the following script to create a powershell script to update the app. IMHO: PowerShell solution is better than an external update app: script is transparent and no additional overhead for background services that lives outside of your app.
Don't forget to inject your variables:
# We don't need progress bars to consume CPU
$ProgressPreference = 'SilentlyContinue'
# Stopping the current app
$appDll = '{assemblyName}.dll'
Stop-Process -Id {processId} -Force
$appFolder = '{folderPath}'
Set-Location -Path $appFolder
# Source file location
$source = '{updateLink}'
# Destination to save the file (folder of the script)
$updateName = Get-Date -Format 'up_dd_MM_yyyy_HH_mm'
$updateNameFile = $updateName + '_update.zip'
$updateZipPath = Join-Path -Path $appFolder -ChildPath $updateNameFile
# Download the update
Invoke-WebRequest -Uri $source -OutFile $updateZipPath
# Classic Unzip
Expand-Archive -Path $updateZipPath -DestinationPath $appFolder -Force
# Cleaning
Remove-Item -Path $updateZipPath
Start-Process -FilePath 'dotnet' -ArgumentList $appDll

SpecsFor.Mvc Build failed

Attempting to test out SpecsFor.Mvc, unforunitly I'm getting this strange build error when I try to run a test.
Running in both my own project and the SpecsFor latest source I get a "Build failed." ApplicationException from the IISTestRunnerAction class. The following is from the log file but its beyond my understanding.
Using visual studio 2012 pro and IIS Express 8.0
The following is from the log file:
Using "VSMSDeploy" task from assembly "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll".
Task "VSMSDeploy"
Package/Publish task Microsoft.Web.Publishing.Tasks.VSMSDeploy load assembly Microsoft.Web.Deployment, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Package/Publish task Microsoft.Web.Publishing.Tasks.VSMSDeploy load assembly Microsoft.Web.Delegation, Version=7.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Starting Web deployment task from source: manifest(C:\Users\Chris\Desktop\SpecsFor-master\SpecsFor.Mvc.Demo\obj\Test\Package\SpecsFor.Mvc.Demo.SourceManifest.xml) to Destination: package(C:\Users\Chris\Desktop\SpecsFor-master\SpecsFor.Mvc.Demo\obj\Test\Package\SpecsFor.Mvc.Demo.zip).
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.targets(4007,5): error : Web deployment task failed. (The type initializer for 'Microsoft.Web.Deployment.DeploymentManager' threw an exception.)
Package failed.
Done executing task "VSMSDeploy" -- FAILED.
UPDATE
Here is the AssemblyStartup
[SetUpFixture]
public class AssemblyStartup
{
private SpecsForIntegrationHost _host;
[SetUp]
public void SetupTestRun()
{
var config = new SpecsForMvcConfig();
//SpecsFor.Mvc can spin up an instance of IIS Express to host your app
//while the specs are executing.
config.UseIISExpress()
//To do that, it needs to know the name of the project to test...
.With(Project.Named("SpecsForTesting"))
//And optionally, it can apply Web.config transformations if you want
//it to.
.ApplyWebConfigTransformForConfig("Debug");
//In order to leverage the strongly-typed helpers in SpecsFor.Mvc,
//you need to tell it about your routes. Here we are just calling
//the infrastructure class from our MVC app that builds the RouteTable.
config.BuildRoutesUsing(r => SpecsForTesting.RouteConfig.RegisterRoutes(r));
//SpecsFor.Mvc can use either Internet Explorer or Firefox. Support
//for Chrome is planned for a future release.
config.UseBrowser(BrowserDriver.Chrome);
//Does your application send E-mails? Well, SpecsFor.Mvc can intercept
//those while your specifications are executing, enabling you to write
//tests against the contents of sent messages.
config.InterceptEmailMessagesOnPort(13565);
//The host takes our configuration and performs all the magic. We
//need to keep a reference to it so we can shut it down after all
//the specifications have executed.
_host = new SpecsForIntegrationHost(config);
_host.Start();
}
//The TearDown method will be called once all the specs have executed.
//All we need to do is stop the integration host, and it will take
//care of shutting down the browser, IIS Express, etc.
[TearDown]
public void TearDownTestRun()
{
_host.Shutdown();
}
}
I had this error come up, and it turned out that I had added a new project to my solution. The new project did not include the same configurations i.e. the solution was running of "Test" but my new project only had the default ones of debug and release.
Go into the Configuration Manager and check that all the projects in your solution have the same configurations in place.
If you are looking for the build log, it is outputted to Console by default. Here is how to capture Console output:
var stringWriter = new StringWriter();
try
{
// Build log is sent to console, redirect output to StringWriter
Console.SetOut(stringWriter);
_host.Start();
}
catch (ApplicationException ex)
{
throw new Exception("Build failed. Output: " + stringWriter, ex);
}
It looks like the error is actually from MSDeploy, which SpecsFor.Mvc uses internally through MSBuild to publish your site for testing. Here's the same error directly from MSDeploy: Web deployment task failed. (The type initializer for 'Microsoft.Web.Deployment.DeploymentManager' threw an exception.). Unfortunately there doesn't seem to be a resolution.
Can you try deploying your site manually? This command line should do the trick:
msbuild /p:DeployOnBuild=true;DeployTarget=Package;_PackageTempDir=;AutoParameterizationWebConfigConnectionStrings=false;Platform=AnyCPU
Let me know if that works or if it blows up with a similar error.
I had exactly the same issue trying to get SpecsForMvc working on a Bamboo remote build agent. Matt Honeycutt's answer pointed me in the right direction. I just had to install MS Web Deploy 3.5 on the VM running the agent to fix this error.
I also needed to install IIS Express 8 on the same VM to allow the SpecsForIntegrationHost to spin up a site in.
arni's answer helped me better diagnose the problem, but also caused me some issues later down the line, when I was having trouble with permissions trying to connect to a remote SQL Server from the tested app. These exceptions were not caught by the ApplicationException catch block as they were of class SystemException. They got handled by the global exception handler, bypassing the end of test cleanup which was supposed to shut down the integration host. This left the IIS Express instance for each test running in the background. (As I can't comment on arni's answer, I've added my amended code here)
var stringWriter = new StringWriter();
try
{
// Build log is sent to console, redirect output to StringWriter
Console.SetOut(stringWriter);
_host.Start();
}
catch (Exception ex)
{
_integrationHost.Shutdown();
throw new Exception("Build failed. Output: " + stringWriter, ex);
}