Service Fabric Debugging with CodePackageDebugParameters - c#

When a new service fabric application is created inside VS the default template adds debugging magic to the scripts so that an application running inside service fabric can be debugged. The powershell scripts passes the _WFDebugParams_ as application parameters to the cluster. I can't figure out to get it working in code. The code I'm currently using is
var debugParameters = new CodePackageDebugParameters(
"MyApplicationPkg",
"Code", null, null,
"Main",
#"C:\Program Files\Microsoft Visual Studio 15.0\Common7\IDE\Remote Debugger\x64\VsDebugLaunchNotify.exe",
"{625F9A8A-16A1-42E6-948F-D5D9AF04F1AB} -p[ProcessId] - tid [ThreadId]",
null, null, null, null, null, null, null);
nameValueCollection["_WFDebugParams_"] = CodePackageDebugParameters.GetDebugParameters(new[] { debugParameters });
await app.CreateApplicationAsync(new ApplicationDescription(ApplicationName, ApplicationTypeName, ApplicationTypeVersion.ToString(), nameValueCollection)).ConfigureAwait(false);
I have only VS2017 installed on my machine with the remote debugger tools. My questions are the following:
What path should be used for the VsDebugLaunchNotify?
How is the GUID
determined (I currently paste in a random GUID as debug parameters)?
Another problem that I have is that CodePackageDebugParameters is basically unusable. I had to copy paste the whole class definition into my project because the ctor and all the properties are internal.

In summary, the GUID is a correlation id of a named pipe set up by Visual Studio Debugger. It is later used by Service Fabric Cluster to ping VS back with process id and thread id that it should auto-attach to.
Here is the more detailed explanation of what is happening when you hit F5 in Visual Studio (Please note that this is a result of investigation done on my local dev environment and might not be 100% accurate as parts of this is not covered by documentation for VS or SF):
Service Fabric Extension scans solution that is about to be debugged and lists all SF services to be deployed into local cluster
For each service it runs StartListener method using undocumented debugger interface IVsDebugLaunchNotifyListenerFactory110. So if there are x services in the project there will be x notifiers started
This in turn creates a named pipe called MicrosoftVisualStudioProcessLaunchNotify_{<<GUID>>} where the GUID part is generated for every function call
Service Fabric Extension deploys SF application passing the GUID in _WFDebugParams_ as indicated in the question.
During service startup, SF uses the _WFDebugParams_ to run VsDebugLaunchNotify.exe passing the GUID, ProcessID of service that was started and ThreadID debugger should auto-attach to.
NOTE: It looks that StartListener can only be used from inside the Visual Studio Extension.

Service Fabric Tools uses this WFDebugParams parameter, so when service fabric application that is being debugged can attach to VS debugger. It is not meant to be used by end user.

Related

Unable to start an NServiceBus Windows Service

Problem Description
I have a Windows service which is hosting an NServiceBus endpoint in NServiceBus.Host.exe.
The binaries are deployed to c:\inetpub\bus\services\myService folder on the server.
A DSC script makes sure the Windows service is created/exists on the server, with the "path to executable" property of the service set to "c:\inetpub\bus\services\myService´NServiceBus.Host.exe" -service NServicebus.Production.
Note! The -service switch is added when installing the service by using the built-in NServiceBus.Host.exe /install parameter, which is why I added it to the Windows service executable path in the DSC script.
Now, when I try to start the service manually on the server, it yields the following error message
Windows could not start the <service name> service on the Local Computer.
Error 1053: The service did not respond to the start or control request in a timely fashion.
Debugging Steps
I have looked through the event log and the following two error messages sticks out:
NServiceBust.Host.exe error:
Application: NServiceBus.Host.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info:
Topshelf.Exceptions.ConfigurationException
at Topshelf.Internal.Actions.RunAsServiceAction.Do(Topshelf.Configuration.IRunConfiguration)
at Topshelf.Runner.Host(Topshelf.Configuration.IRunConfiguration, System.String[])
at NServiceBus.Host.Program.Main(System.String[])
Local Activation permission error:
The application-specific permission settings do not grant Local
Activation permission for the COM Server application with CLSID
{D63B10C5-BB46-4990-A94F-E40B9D520160}
and APPID
{9CA88EE3-ACB7-47C8-AFC4-AB702511C276}
to the user <my_service_account_user> SID (<service_account_SID>) from
address LocalHost (Using LRPC) running in the application container
Unavailable SID (Unavailable). This security permission can be modified
using the Component Services administrative tool.`
Note! The error above only occurs once, i.e. the first time I try to start the service. It does not appear again in the event log for any subsequent attempts of starting the service.
What I have done so far:
Tried the suggestions in a closely related post here on SO, none of which were working.
Tried to install the service by using using the NServiceBus.Host.exe /install parameter. In this case, the service name is created with its name on the following format: MyService.EndpointConfig_v1.0.0.0. Using this approach, the service starts successfully without any error message
Stopping the service and then try to start the service created by the DSC script (with a different name) => success
Removing the service created by NServiceBus and then trying to start the DSC-created service again => failure
Tried granting the service account used for logon when running the service various privileges (neither of which yielded any success), among others:
Membership in the Administrators group
Membership in the Performance Log Users group
Full DCOM permissions via "Launch and Activation Permissions" in dcomcnfg
Tried running c:\inetpub\bus\services\myService´NServiceBus.Host.exe NServicebus.Production from the CLI => success
Code
My Init() method for the service looks like this:
namespace MyService
{
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomLogging, IWantCustomInitialization
{
public void Init()
{
Directory.SetCurrentDirectory(System.AppDomain.CurrentDomain.BaseDirectory);
SetLoggingLibrary.Log4Net(() => XmlConfigurator.Configure(File.OpenRead(#"log4net.config")));
GlobalContext.Properties["Hostname"] = Dns.GetHostName();
GlobalContext.Properties["Service"] = typeof(EndpointConfig).Namespace;
var container = new WindsorContainer(new XmlInterpreter());
Configure.With()
.CastleWindsorBuilder(container)
.XmlSerializer()
.MsmqTransport()
.IsTransactional(true)
.PurgeOnStartup(false)
.IsolationLevel(System.Transactions.IsolationLevel.RepeatableRead);
var connectionString = ConfigurationManager.ConnectionStrings["<some_conn_string>"].ConnectionString;
container.Register(
Component.For<IDatabaseProvider>()
.ImplementedBy<DatabaseProvider>()
.DependsOn(Property.ForKey("connectionString").Eq(connectionString)));
}
}
}
Theory
When installing the service using /install I assume that NServiceBus.Host.exe does some black magic under the hood - e.g. grants some necessary permissions - to make the service able to start.
Note! On the server, the latest version of NServiceBus is installed (v6.x). However, in my solution/service project version 2.x is used (please, do not ask if I can upgrade - unfortunately, that is not an option).
Appreciate any help I can get, as I am running out of ideas.
EDIT 1
I was asked why I can't just use the /install parameter of NServiceBus and be happy with that. The answer to that is that I could (and, actually, I currently am).
The reason I have still posted this question is split:
I wish to understand why one of two seemingly equivalent approaches fails
I am not completely happy with using the /install parameter. The reason? It boils down to a "chicken or the egg" problem. I use Powershell DSC to provision servers in Azure and I believe that ensuring that Windows Services exists on the server is the responsibility of DSC. However, the first time a server is provisioned the services cannot exist unless I script their creation with DSC, and point the executable path to where the service binaries will be deployed whenever that happens. The other alternative is to skip service creation in DSC, and run the NServiceBus.Host.exe /install as a part of the service/application deployment script instead. Obviously, deployment cannot happen until after a server has been provisioned. Thus, it requires the Windows Service part of the DSC script being stripped down to e.g. merely ensuring the service exist - a verification which will fail until a first time deployment of the application has been performed.

Why is my WCF service not working in Test Project?

Something strange is happening. I have a WCF service using C# and Visual Studio 2015 up and running.
This service is published to my local IIS and I have a test website where I can consume my services and display results. The website is running in the visual studio IIS on a generated port.
I have a test project which is where I'm experiencing a problem. In the test project I run the same code that works in the website. However when I debug it my wcf result is already out of context.
The test fails
The service result 'does not exist in the current context' when debugging.
[TestMethod]
public void Test_GetListOfFastPlans()
{
FastPlanFileShareServiceClient client = new FastPlanFileShareServiceClient();
ListSharedFastPlansResult thisismyresult = client.ListOfSharedFastPlans("asdf", "asdf", null, null, null, false);
Assert.IsTrue(thisismyresult.ServiceResult.WasSuccessful);
}
I can step through the entire code block from creating the client to making the call and finally the assertion without any errors. however, the resultclass and the client are never in context.
I don't know what is happening or how to diagnosis the issues.
As it turns out I was running in Release mode. When I switched it to Debug mode I was able to get context on my objects and step through the code as expected. I have not researched this in detail, if anyone has a specific reason on why a proxy service does this please add it.
I used proxy in my server And that created a problem.by deleting Proxy problem is solved.

Expression Encoder 4 in a WCF service

I am trying to write a WCF service that would run in IIS 8 and would use the Expression Encoder SDK to open a video file and then encode it as a WMV. The following code works fine when it's in a desktop application I wrote earlier.
Job job = new Job();
job.ApplyPreset(Preset.FromFile(HttpRuntime.AppDomainAppPath + "Profiles\\" + profile + ".xml"));
job.CreateSubfolder = false;
job.SaveJobFileToOutputDirectory = false;
job.OutputDirectory = Path.GetDirectoryName(input);
MediaItem item;
item = new MediaItem(input);
item.OutputFileName = "{Original file name}.wmv";
job.MediaItems.Add(item);
job.EncodeProgress += new EventHandler<EncodeProgressEventArgs>(job_EncodeProgress);
job.EncodeCompleted += new EventHandler<EncodeCompletedEventArgs>(job_EncodeCompleted);
job.Encode();
But when I try to run this code in a WCF service running on IIS I get the following error
The type initializer for 'Microsoft.Expression.Encoder.SkuManager' threw an exception.
at Microsoft.Expression.Encoder.SkuManager.IsFeaturedSupported(Feature feature)
at MS.Internal.Expression.Encoder.FastProperties.FastPropertyCreate.ShouldAddProp(IFastProperty property, PropertyType propType)
at MS.Internal.Expression.Encoder.FastProperties.FastPropertyCreate.CreatePropertiesArray[T](Type classType, PropertyType propType)
at MS.Internal.Expression.Encoder.FastProperties.FastPropertyCreate.GetProperties[T](PropertyType propType)
at MS.Internal.Expression.Encoder.Persistence.JobPersistence.GetJobFilePropertiesCore[T](JobPropertiesMode mode)
at MS.Internal.Expression.Encoder.Persistence.JobPersistence.GetJobFileProperties[T](JobPropertiesMode mode)
at Microsoft.Expression.Encoder.JobBase.CreateDefaultValues(JobBase job)
at Microsoft.Expression.Encoder.JobBase..ctor()
at Microsoft.Expression.Encoder.Job..ctor()
I can run this code in a regular desktop application on the server, but not in a WCF service running on the same machine.
It turns out it was a permissions problem in IIS.
In order for any program to use the Expression Encoder SDK it needs to be running under an identity that can access the Expression Encoder program installed on the machine.
So in IIS the "ApplicationPoolIdentity" identity that the WCF service was running on didn't have permissions to launch the Expression Encoder program that was installed on the machine by the "Administrator" account.
To fix this you can do one of two things.
When you are installing Expression Encoder allow "All Users" to be able to launch it.
When you install your WCF service on IIS make sure it's running in an application pool that can launch Expression Encoder
I had this same issue in an iis8 web site (not hosting any wcf service tho) and yes i also discovered that IIS needs to run under permissions that can execute expression encoder. BUT one day it just stopped working and started throwing the same error:
"The type initializer for 'Microsoft.Expression.Encoder.SkuManager' threw an exception."
Even though the AppPool's identity was a good one. I pulled my hair out for a day or so then realized that somehow the binaries that VS copies to the local bin directory didn't want to be run in IIS. Somehow corrupted or dll mismatch with expression's installation???. I had to delete the contents of the bin directory and, then VS replaced them, and it worked. Setting CopyLocal to false for those references did not work (conceivably it might be nice to just use from the gac).

how to host silverlight project local

i want to debug my program but i can't host my silverlight project in VS 2010
here is the message that the VS send to me:
"the Silverlight project you are about to debug uses web service. Call to the web service will fail unless the Silverlight is host and launched from the same web project contains the web service"
when I search about it in the web i saw that the problem is that I'm not doing it local
so when I tried to change this line
endpoint address="http://xxx.xx.x.x/WebService/Service1.svc"
to
endpoint address="http://localhost/WebService/Service1.svc"
on this file:
ServiceReferences.ClientConfig
update!!
i tried now to do it like this:
endpoint address="http://localhost:54502/Service1.svc"
and i got and error that says:
the remote server returned an error:NotFound
here:
public int EndAddParticipant(System.IAsyncResult result) {
object[] _args = new object[0];
int _result = ((int)(base.EndInvoke("AddParticipant", _args, result)));
return _result;
what should i do to change it?
i saw that i need to turn on the debug in web.config file but it was already on.
You didn't explain well so here are a bunch of answers:
When you created your solution, you should have told it to host in a web site.
You can do this after the fact but it is a lot of work (for a new guy), you're better off starting over and copying your code from your silverlight project.
If you did but you are trying to connect to another web site as your web service, you will have to implement a Cross Domain configuration file. This opens a big security hole though.
If you have the 2 projects, but your issue is just the "ServiceReferences.ClientConfig" file not pointing the the right server, you need to include the PORT when debugging locally. It should look something like this:
http://localhost:12345/Service1.svc
Where 12345 is the port of your local web service. You can find this out by looking at the "Web" tab of your project properties.
Hope one of these does it. If not, please provide a little more info, like all the important stuff behind the phrase, "it didn't work"!

How do you debug a Windows Service?

I read the MSDN article on the topic. To quote:
Because a service must be run from
within the context of the Services
Control Manager rather than from
within Visual Studio, debugging a
service is not as straightforward as
debugging other Visual Studio
application types. To debug a service,
you must start the service and then
attach a debugger to the process in
which it is running. You can then
debug your application using all of
the standard debugging functionality
of Visual Studio.
Now my problem is that my service fails to start in the first place. First it crashes, and says:
An unhandled exception
(System.Runtime.InteropServices.COMException)
occurred in MyServiceName.exe[3596])
and suggests me to debug it (the debugger instance instantly crashes when I choose one). Then it says
Could not start the MyServiceName
service on Local Computer. Error
1053: The service did not respond to
the start or control request in a
timely fashion
So, how can I investigate/debug the reason that my service won't start? The thing is I created a console application that does EXACTLY what the service does and it works fine. (I mean I just copied the OnStart() method's and the main loop's contents to main).
Any help would be appreciated.
The Service is written in C# with heavy use of interop. I am using VS2008
You could use a parameter to let your application decide whether to start as service or regular app (i.e. in this case show a Form or start the service):
static void Main(string[] args)
{
if ((1 == args.Length) && ("-runAsApp" == args[0]))
{
Application.Run(new application_form());
}
else
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
}
Now if you pass the parameter "-runAsApp" you can debug the application normally - the SCM won't pass this parameter, so you can also use it as service w/o any code change (provided you derive from ServiceBase)
Edit:
The other difference with windows services is identity (this might be especially important with InterOp) - you want to make sure you are testing under the same identity in "app" mode as well as service mode.
To do so you can use impersonation (I can post a C# wrapper if it helps, but this can be easily googled) in app mode to use the same identity your windows service will be running under i.e. usually LocalService or NetworkService.
If another identity is required you can add settings to the app.config that allow you to decide whether to use credentials, and if so which user to impersonate - these settings would be active when running as app, but turned off for the windows service (since the service is already running under the desired identity):
<appSettings>
<add key="useCredentials" value="false"/>
<add key="user" value="Foo"/>
<add key="password" value="Bar"/>
</appSettings>
I usually just manually set a breakpoint, then point it to the currently open project in c#. The code to set a breakpoint is:
System.Diagnostics.Debugger.Break();
That should get you started, then you can just step through your code and see what's really happening.
I stole this from C. Lawrence Wenham, so I can't really take credit, but you can programmatically attach a debugger to a service, WITHOUT breaking execution at that point, with the following code:
System.Diagnostics.Debugger.Launch();
Put this in your service's OnStart() method, as the first line, and it will prompt you to choose an instance of VS to attach its debugger. From there, the system will stop at breakpoints you set, and on exceptions thrown out. I would put an #if DEBUG clause around the code so a Release build won't include it; or you can just strip it out after you find the problem.
You can use WinDbg/NTSD (another debugger from the "Debugging tools for windows" package) to start a debugger together with your service.
To do this open "gflags" (also available in the above mentioned package) to the "Image file" tab and set the path to debugger executable for your image file (service);
If your service is marked as interactive (only possible if it runs under the SYSTEM account) you can directly start WinDbg, just set the debugger to something like "PATH_TO_WINDBG\windbg.exe -g -G" (the -g / -G are needed so that the debugger doesn't break execution on application start or end - the default behaviour). Now when starting your service the windbg window should pop-up and will catch any unhandled exception.
If your service is not interactive you can start the NTSD debugger (a command line debugger) in remote mode and connect to it from WinDbg (that can even be running in another PC). To do this set the debugger in gflags to something like "PATH_TO_NTSD\ntsd -remote tcp:port=6666,server=localhost". Then connect to the remote debugger by starting windbg with something like "windbg -remote tcp:port=6666,server=localhost" and you should have complete control over the other debugging session.
As for finding the source of the exception itself a windbg tutorial is over the topic here but as a start try to execute the "!analyze -v" command after the exception was caught - with some luck this is all information you'll need..
Note: maybe this is overkill for your case but with this approach you can even debug services during system start-up (I had once a timing problem with a service had an issue only when starting the first time with the system)
One thing I do (which may be kind of a hack) is put a Thread.Sleep(10000) right at the beginning of my OnStart() method. This gives me a 10-second window to attach my debugger to the service before it does anything else.
Of course I remove the Thread.Sleep() statement when I'm done debugging.
One other thing you may do is the following:
public override void OnStart()
{
try
{
// all your OnStart() logic here
}
catch(Exception ex)
{
// Log ex.Message
if (!EventLog.SourceExists("MyApplication"))
EventLog.CreateEventSource("MyApplication", "Application");
EventLog.WriteEntry("MyApplication", "Failed to start: " + ex.Message);
throw;
}
}
When you log ex.Message, you may get a more detailed error message. Furthermore, you could just log ex.ToString() to get the whole stack trace, and if your .pdb files are in the same directory as your executable, it will even tell you what line the Exception occurred on.
Add lots of verbose logging in your OnStart. It's painful and old school, but it works.
Seems like the problem is with the user context. Let me confirm whether my assumptions are right.
When you say that the code works perfectly from console application, I assume you are executing the Console application under the same user which you had logged in.
When you say that the same code crashes while called from the windows service, I assume the service is running in "Local System" account in your development machine.
If both my assumptions are right, please try out the following steps.
In the services listing right-click your service, select properties and then "Log On" tab.
Select the option "This account" and provide the existing username and password.
Now try starting the service. It should now start without any errors.
Following could be the root cause of your error
If you are using SQL Server make sure you are not using SSPI authentication.
If you are trying to read any shared folder\resource which you don't have permission when using "local system" account.
If any of the required dependencies required by the application is in a different folder which the "Local System" user doesn't have permission to access.
If you are using VBA automation which wont work in "Local System" account.
Try disabling your firewall or antivirus.
You could add some logging around the interop calls to find out which one fails.
Also services by default aren't associated with a desktop; if you open the services.msc control panel applet, get the properties of your service, go to the "Log On" tab, you could check "Allow service to interact with desktop". This could fix the problem for you in some cases.
I would assume the reason could be causing because of heavy use of interops. So you need to tackle this problem differently. I would suggest create a windows or console app with same logic of you service and make sure that it works first without any issues, and then you may want to go with creation of the Win service.
Debugging services is a pain, particularly since startup seems to be when many of the problems manifest (at least for us).
What we typically do is extract as much of the logic as possible to a single class that has start and stop methods. Those class methods are all that the service calls directly. We then create a WinForm application that has two buttons: one to invoke start, another to invoke stop. We can then run this WinForm applicaiton directly from the debugger and see what is happening.
Not the most elegant solution, but it works for us.
Check out this question, which discusses how to catch unhandled exceptions in a window service.
In order to attach a debugger to the Windows Service, it needs to be started first. The reason why the service failed to start can be checked in Windows Event Log.
After that the process of attaching a debugger is pretty straight forward from Visual Studio Debug->Attach To Process.
What I've done is implemented by OnStart() to look something like this:
_myBusinessObject = new MyBusinessObject();
After the Business Object has been constructed, timers and IPC handlers do all the real (Service) work.
Doing it like this allows you to create a Forms/WPF application that call the same code above in the Form_Loaded handler. This way, debugging the Forms application is the exact same as debugging the Service.
The only issue is that if you are using app.config values, there will be a second app.config file that needs to be kept up-to-date.
Use following Code in Service OnStart Method:
System.Diagnostics.Debugger.Launch();
Choose Visual Studio option from Pop Up message
read the 2 articles mentioned here:
http://geekswithblogs.net/BlackRabbitCoder/archive/2011/03/01/c-toolbox-debug-able-self-installable-windows-service-template-redux.aspx
Step 1 - Add #if region to your Program.cs
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new StockInfoService()
};
ServiceBase.Run(ServicesToRun);
#if (!DEBUG)
ServiceBase[] ServicesToRun = new ServiceBase[] { new SqlBackupService() };
ServiceBase.Run(ServicesToRun);
#else
StockInfoService service = new StockInfoService();
service.OnStart();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#endif
}
Step 2 - In Service.cs change your OnStart(string[] args) method without parameter one. (I commended mine.)
public void OnStart()
//protected override void OnStart(string[] args)
{
**Do your thing.
}
Step 3 - Simply hit Start (F5) and debug your code.

Categories