Problem with building C# code in Windows Service App - c#

I have some server app. This app run, read some files, create C# classes, build this and load assembly. This app can work in two modes - one mode is window desktop application, and other mode - as windows service but core in dll is common.
Sometimes when this app work long time as service, and machine server has long timeup, they can't build anything. I attach to debugger, and debug. I debug .NET source (CompileAssemblyFromSource), and I see, that .NET classes just run csc.exe process with some params (CSharpCodeProvider class), but csc.exe run, return no errors or exceptions, output is blank and nothing is happend. No assembly is build.
I wrote some dump test service to compile code:
namespace CompilerService
{
public class Compiler
{
private Task _compilerTask;
public Compiler()
{
_compilerTask = Task.Run(() => CompileHalloWorld());
}
private const string _workingDir = #"C:\tmp";
private void CompileHalloWorld()
{
System.Threading.Thread.Sleep((30000));
if (!Directory.Exists(_workingDir))
{
Directory.CreateDirectory(_workingDir);
}
Directory.SetCurrentDirectory(_workingDir);
var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
parameters.GenerateExecutable = true;
CompilerResults results = null;
try
{
results = csc.CompileAssemblyFromSource(parameters,
#"using System;
class Program {
public static void Main(string[] args) {
Console.WriteLine(""Hallo World!"");
}
}");
}
catch (Exception e)
{
int a = 2;
}
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
}
}
}
This dump service is fail too with build hallo world in this state of machine.
After restart machine, all work again ok, compile and load assembly all the time. After few weeks, problem come back, and we must reset server. This problem is on only one machine. On otger machines this service and csc.exe work perfect from years.
If machine is in this wird state, csc.exe dont build in windows service app, but when We run this app as Windows Desktop App all work fine, and csc.exe build normal...
Can you tell me, this is some known issue, oraz is some solution of don't compile csc.exe without machine restart?

Related

How do I compile an XNA project from C# with MSBuild 14?

I have an XNA project I have that compiles perfectly fine in Visual Studio 2015, that makes use of C# 6 features.
Previously, I had some tools coded in C# that would auto-compile the project when it was using C# 5 under VS 2013, but the change to C# 6 has broken things somehow.
To reproduce this I created a new console application, referenced Microsoft.Build, Microsoft.Build.Framework, and Microsoft.Build.Utilities.Core assemblies from C:\Program Files (x86)\MSBuild\14.0\Bin.
I then created my C# compiler project with the following code:
namespace CompileXna
{
class Program
{
static void Main(string[] args)
{
const string solutionPath = #"D:\Code\My Projects\FrbTest\FrbTest.sln";
var properties = new Dictionary<string, string>()
{
{"Configuration", "Debug"},
{"Platform", "x86" }
};
var parameters = new BuildParameters
{
Loggers = new ILogger[] {new BuildLogger()}
};
var request = new BuildRequestData(solutionPath, properties, null, new string[] {"Build"}, null);
var manager = BuildManager.DefaultBuildManager.Build(parameters, request);
Console.WriteLine("Done");
Console.ReadLine();
}
}
class BuildLogger : Logger
{
public override void Initialize(IEventSource eventSource)
{
eventSource.ErrorRaised += (sender, args) =>
Console.WriteLine($"Error: File {args.File} line {args.LineNumber} message {args.Message}");
eventSource.WarningRaised += (sender, args) =>
Console.WriteLine($"Warning: File {args.File} line {args.LineNumber} message {args.Message}");
}
}
}
Unfortunately, when this runs I get the following error:
Error: File C:\Program Files (x86)\MSBuild\Microsoft\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.ContentPipeline.targets line 78 message The "BuildContent" task could not be instantiated from the assembly "Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553". Please verify the task assembly has been built using the same version of the Microsoft.Build.Framework assembly as the one installed on your computer and that your host application is not missing a binding redirect for Microsoft.Build.Framework. Unable to cast object of type 'Microsoft.Xna.Framework.Content.Pipeline.Tasks.BuildContent' to type 'Microsoft.Build.Framework.ITask'.
I tried looking in the details of the build output in Visual Studio 2015 when it successfully compiles my XNA project, but even with Detailed logging all I could find (seemingly) relevant was:
1>Using "BuildContent" task from assembly "Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553".
1>Task "BuildContent"
1>Done executing task "BuildContent".
Anyone have any success on this?

How to connect to windows phone 7 from a 64-bit application

I have a 32-bit program (written in C++) that can connect to some different devices and as long as it is 32-bit everything works fine. However, now I need to build it as a 64-bit program but then I came across some problems with Windows Phone 7.
I found out that a dll (written in C#) that I rebuilt as 64-bit throws exception at this line:
MultiTargetingConnectivity connectivity = new MultiTargetingConnectivity(CultureInfo.CurrentUICulture.LCID);
The exception is:
An unhandled exception of type 'Microsoft.SmartDevice.Connectivity.DatastoreException' occurred in Microsoft.SmartDevice.Connectivity.dll
Additional information: Retrieving the COM class factory for component with CLSID {349AB2E8-71B6-4069-AD9C-1170849DA64C} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
(For example, if I try to run this example program it works in 32-bit but throws that exception in 64-bit at the same line)
When I searched for that CLSID in the registry I found a path to to "C:\Program Files (x86)\Common Files\Microsoft Shared\Phone Tools\CoreCon\11.0\Bin\ConMan2.dll" so I registered that dll using regsvr32 but I still get the same exception.
UPDATE:
Since I might need to create a workaround instead of finding a 64bit version of ConMan2.dll, I post a bit of my current dll here if anybody can show me a possible workaround so that it will work in both 32 and 64 bit.
namespace WP7DLL
{
// Interface declaration.
[Guid("11111111-1111-1111-1111-111111111111")]
public interface IWP7DLL
{
int GetStatus();
};
[ClassInterface(ClassInterfaceType.None)]
[Guid("22222222-2222-2222-2222-222222222222")]
public class WP7DLL : IWP7DLL
{
public WP7DLL() { }
public int GetStatus()
{
//Line that gives an exception in 64 bit
MultiTargetingConnectivity connectivity = new MultiTargetingConnectivity(CultureInfo.CurrentUICulture.LCID);
...
...
}
}
}
The COM server with CLSID = {349AB2E8-71B6-4069-AD9C-1170849DA64C} is implemented in C:\Program Files (x86)\Common Files\Microsoft Shared\Phone Tools\CoreCon\11.0\Bin\ConMan2.dll
There’s no 64-bit version of that DLL.
And you can’t use a 32-bit DLLs directly from a 64 bit process.
There’s a workaround. You can create another project, 32-bit EXE, that will call that 32-bit DLL however you want, and implement any IPC to interact with your main 64-bit application.
For the specific IPC mechanism, if you only need to invoke a single relatively long task and wait for it to complete, command-like app + command-line arguments + exit code may me enough for you.
If you need to issue many calls, I’d choose WCF over named pipe transport. If you’ll choose this way, below is some sample code implementing that .EXE.
/// <summary>The class from the shared assembly that defines WCF endpoint, and named events</summary>
public static class InteropShared
{
// Host signals it's ready and listening. Replace the zero GUID with a new one
public static readonly EventWaitHandle eventHostReady = new EventWaitHandle( false, EventResetMode.AutoReset, #"{00000000-0000-0000-0000-000000000000}" );
// Client asks the host to quit. Replace the zero GUID with a new one
public static readonly EventWaitHandle eventHostShouldStop = new EventWaitHandle( false, EventResetMode.AutoReset, #"{00000000-0000-0000-0000-000000000000}" );
const string pipeBaseAddress = #"net.pipe://localhost";
/// <summary>Pipe name</summary>
// Replace the zero GUID with a new one.
public const string pipeName = #"00000000-0000-0000-0000-000000000000";
/// <summary>Base addresses for the hosted service.</summary>
public static Uri baseAddress { get { return new Uri( pipeBaseAddress ); } }
/// <summary>Complete address of the named pipe endpoint.</summary>
public static Uri endpointAddress { get { return new Uri( pipeBaseAddress + '/' + pipeName ); } }
}
static class Program
{
/// <summary>The main entry point for the application.</summary>
[STAThread]
static void Main()
{
// The class implementing iYourService interface that calls that 32-bit DLL
YourService singletoneInstance = new YourService();
using( ServiceHost host = new ServiceHost( singletoneInstance, InteropShared.baseAddress ) )
{
// iYourService = [ServiceContract]-marked interface from the shared assembly
host.AddServiceEndpoint( typeof( iYourService ), new NetNamedPipeBinding(), InteropShared.pipeName );
host.Open();
InteropShared.eventHostReady.Set();
// Wait for quit request
InteropShared.eventHostShouldStop.WaitOne();
host.Close();
}
}
}

Load NuGet dependencies at runtime

I'm looking for a way to run code by executing the following steps:
Receiving a list of NuGet packages (a list of tuples ("package name", "package version", "path to main class").
Retrieving them in a local directory (cf code sample #1)
Loading them in my program at run-time
Running the main classes by introspection (cf code sample #2)
By now I am struggling with the third step. I can't find out how to load my package at run-time.
My main question are:
How can I find out in which folders were stored the retrieved packages?
How can I load the content of those directories into my program?
Code Sample #1:
private static void getPackageByNameAndVersion(string packageID, string version)
{
IPackageRepository repo =
PackageRepositoryFactory.Default
.CreateRepository("https://packages.nuget.org/api/v2");
string path = "C:/tmp_repo";
PackageManager packageManager = new PackageManager(repo, path);
Console.WriteLine("before dl pkg");
packageManager.InstallPackage(packageID, SemanticVersion.Parse(version));
}
Code sample #2:
private static void loadByAssemblyNameAndTypeName(string assemblyName, string typeName)
{
AppDomain isolationAppDomain = AppDomain.CreateDomain("tmp");
object a = isolationAppDomain.CreateInstanceAndUnwrap(assemblyName, typeName);
Type x = a.GetType();
MethodInfo m = x.GetMethod("Main");
m.Invoke(a, new object[] { });
}
Grab a cup of coffee :)
Downloading the nuget package?
Nuget.Core (nuget package) is a good choice, and here is a snippet of code that I have that should be able to download a nuget package by id and version
var repo = PackageRepositoryFactory.Default
.CreateRepository("https://packages.nuget.org/api/v2");
string path = "c:\\temp";
var packageManager = new PackageManager(repo, path);
packageManager.PackageInstalled += PackageManager_PackageInstalled;
var package = repo.FindPackage("packageName", SemanticVersion.Parse("1.0.0"));
if (package != null)
{
packageManager.InstallPackage(package, false, true);
}
Notice that I plugged an event handler to the PackageInstalled event of the PackageManager class.
How do we load an assembly in an isolated app domain?
Since reflection API does not provide a way to load an assembly in a specific domain, We will create a proxy class that act as a loader in our isolated domain:
public class TypeProxy : MarshalByRefObject
{
public Type LoadFromAssembly(string assemblyPath, string typeName)
{
try
{
var asm = Assembly.LoadFile(assemblyPath);
return asm.GetType(typeName);
}
catch (Exception) { return null; }
}
}
And now, is how to put it all together?
Here comes the complex part:
private static void PackageManager_PackageInstalled(object sender,
PackageOperationEventArgs e)
{
var files = e.FileSystem.GetFiles(e.InstallPath, "*.dll", true);
foreach (var file in files)
{
try
{
AppDomain domain = AppDomain.CreateDomain("tmp");
Type typeProxyType = typeof(TypeProxy);
var typeProxyInstance = (TypeProxy)domain.CreateInstanceAndUnwrap(
typeProxyType.Assembly.FullName,
typeProxyType.FullName);
var type = typeProxyInstance.LoadFromAssembly(file, "<KnownTypeName>");
object instance =
domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
}
catch (Exception ex)
{
Console.WriteLine("failed to load {0}", file);
Console.WriteLine(ex.ToString());
}
}
}
Notice that this method is the event handler that gets executed after downloading the nuget package
Also
Note that you will need to replace <KnownTypeName> with the expected type name coming from the assembly (or maybe run a discovery of all public types in the assembly)
Worth noting that I haven't executed this code myself and cannot guarantee that it will work out of the box, and still might need some tweaking. but Hopefully it is the concept that allows you to solve the problem.
Don't do that! You are probably trying to load NuGet content at a customers computer to save some space on distribution of your software. Isn't it that?
The common recommended approach is to download the NuGet content as the second step of an automated build (after downloading the source code), build the software and run the automated tests with the NuGet content you have downloaded. And then distribute the build with the NuGet content you have tested as the complex whole unit.

Script Error when open .chm disappear when opening through the debugger

I get a number of script errors and none of the images will be shown when I open a .chm file on my computer. If I esc all error messages and refresh (twice) then the .chm is shown correctly. Although I need to do this for each new page.
I have made all recommended fixes for .chm files! Reregistrered, unblocked, fixed paths,... The errors is for all .chm on the machine
But, here is my real question, if I run this program, with a .chm file as argument, through the Visual Studio 2013 debugger then the .chm is shown correctly!
The problem is probably in my Windows configuration, but somehow the debugger "fixes" this error and get it to work. Does the debugger have it's own configuration that isn't dependent on the actual Windows configuration?
using System.Diagnostics;
namespace xcute
{
class Program
{
static void Main(string[] args)
{
if (args.Length > 0)
{
string f = args[0];
Process.Start(f);
}
}
}
}
EDIT: Here are the error dialogs
I have found the problem (well sort of)!
If I open the .chm as administrator then everything works! So obviously I have some permission error on my computer. The reason it worked when I ran my program in the debugger is that Visual Studio is started as Administrator...
But since I'm a programmer I solved the issue by creating a small program that start hh.exe as admin. I get the UAC consent form but I can live with that.
// Anders
The program:
internal class Program
{
private static void Main(string[] args)
{
if (args.Length > 0)
{
Execute(args[0]);
}
}
private static void Execute(string chmFile)
{
const int ERROR_CANCELLED = 1223; //The operation was canceled by the user.
ProcessStartInfo info = new ProcessStartInfo(#"C:\Windows\hh.exe");
info.Arguments = chmFile;
info.UseShellExecute = true;
info.Verb = "runas";
try
{
Process.Start(info);
}
catch (Win32Exception ex)
{
if (ex.NativeErrorCode == ERROR_CANCELLED)
Console.WriteLine("Why you no select Yes?");
else
throw;
}
}
}

Why do i get Error when i try to run or start my win service?

I have a windows service which i can't run or start, only install or directly debug the project.
This is my main:
namespace MyService
{
public static class Program
{
private static void Main()
{
var ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
}
}
And this is my Service:
public partial class Service : ServiceBase
{
private dynamic _serviceHost;
public Service()
{
this.InitializeComponent();
this.ServiceName = "MyService";
this.CanShutdown = true;
this.CanStop = true;
}
private static string HostName
{
get
{
string hostName = Dns.GetHostName();
IPHostEntry ipHostEntry = Dns.GetHostEntry(hostName);
return ipHostEntry.HostName;
}
}
protected override void OnStart(string[] args)
{
var worker = new Thread(this.InitializeHost) { Name = "Host", IsBackground = false };
worker.Start();
}
private void InitializeHost()
{
var baseAddress = new Uri(string.Format("net.tcp://{0}:{1}/MyService", HostName, "9020"));
var mexAddress = new Uri(string.Format("http://{0}:{1}/MyService", HostName, "8000"));
var cache = Factory.Create<string>("MyAssembly.MyClass", "MyAssembly");
var service = new ServiceWcf<string>(cache);
using (this._serviceHost = new Host<string>(service))
{
this._serviceHost.Open(baseAddress, mexAddress);
}
}
protected override void OnStop()
{
this._serviceHost.Dispose();
}
}
When I try to run without debugging or to start after installing the service i get the following error:
Run (directly or through VS):
Error while trying to run project: Unable to start program
'C:\path\to\my\projects\bin\Release\MyService.exe'.
The system cannot find the specified path.
Service start:
The service "MyService" on local cimpouter could not be started.
Error 3: The system cannot find the specified path.
I have no clue where the error could be.
EDIT:
private void InitializeComponent()
{
this.serviceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller = new System.ServiceProcess.ServiceInstaller();
//
// serviceProcessInstaller
//
this.serviceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller.Password = null;
this.serviceProcessInstaller.Username = null;
//
// serviceInstaller
//
this.serviceInstaller.ServiceName = "MyService";
this.serviceInstaller.DisplayName = "My service";
this.serviceInstaller.Description = "My service is awesome.";
this.serviceInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
//
// ProjectInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller,
this.serviceInstaller});
}
I think this is just an issue with how the service has been registered - i.e. it's in the wrong place.
run an installutil /u [service] from a VS command prompt to uninstall any service entries you already have.
CD over to the folder where you want to run the service from - be careful here, you will have both a debug and a release build - which one do you want to be installed in the services list?
Use installutil /i [service] on the exe to reinstall.
Now it should work.
I think you might have registered the debug build first and have subsequently run a Clean operation on the build before building the Release version; thus deleting the original executable. Either that - or perhaps you moved the project after originally developing it?
Many of the developers I work with use a different folder for their local service installations that is always the same; they then deploy either a debug or release version to it; thus when they want to switch between the two they just copy different file versions over. I don't do this - I only ever register the debug build; but then I have more work to do when testing the release build :)

Categories

Resources