Issues Proffering Language Service - c#

I have found two ways of proffering a language service on the internet.
The first way involves using a IOleComponentManager and registering a timer to call my service during idle times.
The second way involves casing my service as an IServiceContainer and adding a ServiceCreatorCallback to "proffer the service on demand".
Supposedly the second way is now the "preferred way" of doing things. Unfortunately, when I use this method, OnSynchronizeDropdowns never gets called on my TypeAndMembersDropdownBars implementation.
In addition, when my LanguageService finds errors in the file, it uses ParseRequest.Sink.AddError() to add errors to the error list. When proffering "On Demand", these errors don't show up in the GUI, even though I see them being added when I debug through the code.
I know that my language service is being registered, because syntax highlighting, "Go to Defintion", and "Find All References" still work.
Here is the code I'm using to "proffer my service on demand":
IServiceContainer serviceContainer = this as IServiceContainer;
ServiceCreatorCallback callback = new ServiceCreatorCallback(CreateLanguageService);
serviceContainer.AddService(typeof(MyLanguageService), callback, true);
Can anyone tell me why some functionality of my LanguageService does not work when proffering it on demand? Am I missing something, or is that way just not meant for a fully functional language service?

It looks like at least the missing functionality requires using the IOleComponentManager method that registers a timer to call the language service during idle periods.
Using dotPeek, I found that OnSynchronizeDropdowns() gets called from OnCaretMoved() for synchronizing the selected item when you click around in the editor. OnCaretMoved() itself appears to only be called from the LanguageService.OnIdle() method, which I believe requires the use of the idle timer.
After digging some more, I also found that the error list requires that the ParseRequest.Reason be set to ParseReason.Check, otherwise it ignores the call. Digging through the code some more, the only place I found that parse reason being used was in Source.OnIdle().
Update: I believe I have confirmed that registering an idle timer is required for these two pieces of functionality. From MSDN on LanguageService.OnIdle:
Note
This method is not called unless you set up your own timer and call
this method from the timer handler.
The base method calls OnCaretMoved if the caret has moved since last
time OnIdle was called. The base method then calls the OnIdle method
on the Source object for the current view. If the current Source
object cannot be obtained, the base method does nothing at all,
including not calling OnCaretMoved.

Related

When using a proxy to log function calls within a .NET object, what's the best way to capture calls from within the proxied object?

During a recent assignment, I was tasked to test out OpenTelemetry as a way to enhance visibility in our (ASP.NET Core) app. One of the goals I was hoping to achieve involved providing function-level traces throughout each of our services, but a concern we had was the amount of logging boilerplate code this would leave.
DispatchProxy has proven to be a useful tool here, but its downside so far is that the proxy will only be used for the first (outer) function call. Once within a function, all method calls from within that function go through the proxied object rather than the proxy, leaving no trace of these inner function calls. All time spent within the function is either attributed to the parent (when synchronous) or mysteriously missing from the tree (when async).
To demonstrate this issue, I have created a test project which you can clone and run for yourself to follow along with my example. I have left the Honeycomb exporter configuration helper commented out in ServiceCollectionExtensions.ConfigureTelemetry() for those who wish to use that visualization.
From Worker.cs:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// wait for the console to load before we report any activities
await Task.Delay(3000);
using var activity = Telemetry.ActivitySource.StartActivity("Worker Actions");
this.mainService.MethodWithNestedMethod();
this.mainService.CallSecondaryServiceNestedMethod();
this.lifetime.StopApplication();
}
In this image captured from Honeycomb, you can see the 'Worker Actions' activity output from the above code snippet. We see the first call to each proxied service, but any further calls made within those methods are skipping the proxy, and thus our handy logging hook is rendered useless. I've noted the areas where I would've expected a trace for the nested methods to appear.
What I am hoping to determine is if there is a way to instrument my services to capture these inner calls without resorting to manual instrumentation in every single method, whether it is through some existing proxy class like DispatchProxy, an OpenTelemetry helper I've yet to discover, or some other method entirely. We may decide against adopting a paid service if that's the only option, but it would be good to know anyway.

Application call with arguments to already running instance via WCF and wait for string result

First of all: I do really know what Google is and, yes, there are several existing threads for this topic, but I just did not find what I am searching for.
The situation might be complex and hopefully I won't forget to explain anything.
I'll come to the question/problem:
I've got an application, which is only allowed to run once on a system.
So I firstly locked this with a mutex, that's not enough because there is a requirement, that the application must accept command line arguments - even if it's already running.
Ok, I Googled it and finally tried the solution "WCF for Single Instance from codeproject written by KN.Sudha" with some modifications (only some structure issues, nothing that changed the internal behavior). Now I am able to get the already running instance of my application when trying to start a new one (with and without arguments). I can call the methods with [OperationContract] Attribute in my class which inherits from the interface with the [ServiceContract] Attribute.
So far so good.
Now when I call a second instance from a command line with arguments (sure, I mean the application path and then arguments), the call is transmitted over WCF to the first running instance to be executed, but I now want to wait for the result of the call and display the string within my external console, where I started the second instance with the arguments (the second instance exits after the call, the command line is still running for further activities).
If anyone has any idea to solve this, it would be very nice to share with the stackoverflow community :)

Preventing code being loaded to another AppDomain

We have a plugin for excel that is normally working fine, and we don't have anything set up for using AppDomains.
However, some other plugin seems to force our code to load the second time, and we end up having our code running on two different AppDomains (when we want to execute an action, we will put it in a queue on AppDomain 1, and then, the Excels OnTime function runs dequeue method on AppDomain 2, where the queue is empty).
So, my question is this: is there a simple way to get around this problem, maybe prevent our program from being loaded twice or by other AppDomains? Does anyone have any other idea on how to approach this issue?
Update:
What we managed to do, was to load our whole program into other plugin's AppDomain when we are called, and now we have strangest problem at the same places (places that used to be "gateways to other domains", like the mentioned action queue function):
The SynchronizationContext.Current seems to reset to null whenever there is such case, for example for every call of the click handler on ribbon, the SynchronizationContext.Current is set to null.
I even tried debugging the .Net code, and it happens that framework remembers an old synchronization context, and when getting everything back to how things were, old synchronization context is null.
Can anyone give any help on this issue, I'm really starting to lose it?
I think this could be a solution for your problem:
http://ingebrigtsen.info/2007/05/18/cross-appdomain-singleton/
and an update to the post above:
http://web.archive.org/web/20120427003305/http://www.dolittle.com/blogs/einar/archive/2007/05/30/crossappdomainsingleton-update.aspx

Trace your runtime process as any method calling?

hmm, I feel my OP title sounds wrong, but I am not sure how to put it...
I mean something like during the runtime, whenever a button button being click, dialog prompt up, any method being called etc. There will be some output that print out my StackTrace or something that indicates where I am in the code.
The reason being is, I just picked up a new project with very huge source code (62 projects in a solution), so pretty much I always have no idea whenever a Dialog or a View open, where the file is or a method is locate. So I want a good way to keep track on where I am, tell me which files or at least the method that calling it. Then I will know where to set a break point in VS.
But as I stated, the projects is pretty huge, so there is no way I can go to every Class and every method to add Debug.WriteLine("Method XXX being called").
So I wonder is there any way I can make a piece of code being called whenever any method being executed? i.e. Some event handler that will execute whenever method is being call? Or does Visual Studio have a functionality that can help me trace where I am in the code? (i.e Button being click, the last return line is XXXX)
Use a profiling tool.. Try "Ants"
A few things come to mind:
Apsect Oriented Programming
I've used this to weave in code at every method call to do extremely deep tracing. I happened to use Postsharp.
Intellitrace
This is a pretty handy tool from MS. It looks like you can do method call level logging.

Why isn't my ILoadEventListener being called?

I made a class that implements ILoadEventListener, and implemented an OnLoad() method (of course -- else it wouldn't even compile). After creating the "new NHibernate.Cfg.Configuration()", I add it as the documentation says:
configuration.EventListeners.LoadEventListeners = new ILoadEventListener[] {
new MyListener(),
new NHibernate.Event.Default.DefaultLoadEventListener()
};
However, it never seems to get called -- I've added logging statements to my OnLoad() and set a breakpoint there in the debugger -- even when using my app in a way that clearly gets objects from the database using this NHibernate session factory.
What am I missing?
EDIT: I poked around in the source code (the NHibernate event documentation is rather sparse), and found that the event that corresponds to IInterceptor is actually PreLoad, not Load, so I tried using that, and that one does fire. So I can use that for now, but I still don't really know what preload/load/postload are intended to be.
The documentation on this is practically nonexistent, so maybe this will help a few people:
None of the Load events (Load/PreLoad/PostLoad) will ever fire on an entity that is in the identity cache, even if you Get, Load, or query for it again.
This sort of makes sense if you squint at it just the right way, but it makes for a great deal of frustration due to non-deterministic behaviour, since most of the time, you won't know whether or not an entity is in the cache. Evidently, these events refer to the process of hydrating an entity as opposed to simply requesting it.
I haven't tested this theory, but I wouldn't be surprised if cache hits from the L2 cache also don't fire Load events, since those entities won't be hydrated either.
In practice, this means that if you want a particular listener to run on "every" entity, you need to account for the possibility that it was originally a transient instance which was introduced to the session by Save, Update, etc. In other words, if you implement IPostLoadEventListener, you probably also want to implement IPostInsertEventListener and IPostUpdateEventListener.
This won't actually change the behaviour - the listener will still only ever run the very first time an entity becomes associated with the session - but at least this guarantees that every entity you can retrieve from the session has been intercepted by that listener. In my case, I was trying to use PostLoad to inject something into the entity, so this was an acceptable workaround.
If you really need the listener to fire every time an entity is retrieved, you either need to use a stateless session (no cache) or evict the entities before loading/querying again.

Categories

Resources