How to change this from "../ReportApi" automatically when I deployed? - asp.net-core

I've made rdlc reports and view using Syncfusion report viewer and It runs successfully. But, when I deploy it in server then the report could't found. I have to change the path manually from here (the code I've attached)
</script>
<ej-script-manager></ej-script-manager>

In our ASP.NET Core application we are getting the report path from wwwroot folder. So we are using the WebRootPath for getting the wwwroot folder path as shown in below code example. In production side we need to include the report path.
public void OnInitReportOptions(ReportViewerOptions reportOption)
{
string basePath = _hostingEnvironment.WebRootPath;
FileStream inputStream = new FileStream(basePath + #"\ReportData\InvoiceTemplate.rdl", FileMode.Open, FileAccess.Read);
reportOption.ReportModel.Stream = inputStream;
}
Please consult the help documentation for how include the files when publishing the ASP.NET Core application.

Related

Configure NLog in ASP.NET Core 2.0 without nlog.config file

I want to create a NuGet for common things used at any ASP.NET Core application, and I want to add a Log manager inside taking advantage of NLog. Regarding this, following the tutorial on NLog it seems like I am forced to add a nlog.config at any application that is using my own NuGet.
Is there any option to avoid this config file, maybe creating a configuration in code, or at least to embed it on my own NuGet?
Thanks a lot in advance
NOTE: followed NLog getting started tutorial
If you are following the tutorial then you can replace this call:
var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
With your own custom NLog LoggingConfiguration:
var nlogConfig = new NLog.Config.LoggingConfiguration();
var nlogFileTarget = new NLog.Targets.FileTarget("logfile") { FileName = "file.txt" };
nlogConfig.AddRuleForAllLevels(nlogFileTarget);
var logger = NLog.Web.NLogBuilder.ConfigureNLog(nlogConfig).GetCurrentClassLogger();

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

Get XML comments output file location for ASP Core

I've added Swashbucklepackage to my ASP Core project.
I'd like to configure Swagger to use auto-generated by VS xml comments.
The problem is that I can't find the way to get that location:
PlatformServices.Default.Application.ApplicationBasePath - points to the project root path
Directory.GetCurrentDirectory() - the same
Path.GetFullPath(".") - the same
IHostingEnvironment.WebRootPath - the same
Output folder configured in <project>.xproj by BaseIntermediateOutputPath option.
But I can't get this location in runtime.
var pathToDoc = "????";
options.OperationFilter(new Swashbuckle.SwaggerGen.XmlComments.ApplyXmlActionComments(pathToDoc));
Bad solutions I see:
add configuration option to AppSettings.json
Relative path from project path (as I'm configuring bin output path).
But I'd like to use this with Docker, CI, localhost, so I don't think this would be the best solution to use hard-coded solution..
You can try the following function to get the XML File path
private string GetXmlCommentsPath()
{
var app = PlatformServices.Default.Application;
return System.IO.Path.Combine(app.ApplicationBasePath, System.IO.Path.ChangeExtension(app.ApplicationName, "xml"));
}
The xml file has the same name as the app. I am currently using this code in my project and it works fine.

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);
}

How to load file from the Bundle in eclipse & My Eclipse?

This is very strange behavior I have noticed while developing Plugin.
I have a file in the bundle that has to be loaded for wizard.
I tried to load the file in eclipse using following code.
Bundle bundle = Platform.getBundle(MTPAppPlugin.getDefault()
.getBundle().getSymbolicName());
URL fileURL = bundle.getEntry(relativeFilePath);
File file = new File(FileLocator.resolve(fileURL).toURI());
But this didnt worked in MyEclipse.So I used other way for my eclipse
url = new URL("platform:/plugin/"
+ MTPAppPlugin.getDefault().getBundle().getSymbolicName()
+ relativeFilePath);
InputStream inputStream = url.openConnection().getInputStream();
in = new BufferedReader(new InputStreamReader(inputStream));
Now I need to know is there any common way to load the file for eclipse & My Eclipse?
The first one will not work if you have space in your folder path like C:\program files....
The first one seems to be correct. What was the error given in MyEclipse?