I have a COM object which is implemented in C#, and inherits from StandardOleMarshalObject to disable the NTA default behavior. For some reason, when I make a call to a server that makes a reentrant call to the client, the callback ends up on a different thread.
How do I ensure that all calls are made on the main thread?
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IComChat
{
void WriteLine(string text);
void Subscribe(IComChat callback);
}
public class ComChatServer : StandardOleMarshalObject, IComChat
{
private List<IComChat> Clients = new List<IComChat>();
public void WriteLine(string text)
{
foreach (var client in Clients)
{
// this makes a reentrant callback into the calling client
client.WriteLine(text);
}
}
public void Subscribe(IComChat client) => Clients.Add(client);
}
public class ComChatClient : StandardOleMarshalObject, IComChat
{
private IComChat Server;
private Thread MainThread;
public ComChatClient()
{
this.MainThread = Thread.CurrentThread;
this.Server = /* get server by some means */;
this.Server.Subscribe(this);
}
void IComChat.WriteLine(string text)
{
// this throws as the call ends up on a different thread
Contract.Assert(Thread.CurrentThread == MainThread);
Console.WriteLine(text);
}
void IComChat.Subscribe(IComChat callback) => throw new NotSupportedException();
public void WriteLine(string text) => Server.WriteLine(text);
}
public static class Program
{
public static void Main(string[] args)
{
var client = new ComChatClient();
Application.Run(new ChatWindow(client));
}
}
StandardOleMarshalObject only keeps things on the main thread if you create the object on a STA thread. Mark your entrypoint with [STAThread] to set your main thread as being single-threaded:
public static class Program
{
[STAThread]
public static void Main(string[] args)
{
var client = new ComChatClient();
Application.Run(new ChatWindow(client));
}
}
Related
class Program
{
static void Main(string[] args)
{
//I want to call the bird method here
}
public void bird(Program program)
{
birdSpeech();
}
public void birdSpeech()
{
Console.WriteLine("Chirp Chirp");
}
}
How do I call bird in the main, I also tried to call the method from a object of the class but that didn't work
Does it even make sense to do this (I try to avoid static methods as much as possible).
If a method can be made static without changing the code, you should make it static. To answer your question though, you can create an instance of Program in your Main function and call the non-static methods through it.
class Program
{
static void Main(string[] args)
{
var p = new Program();
p.bird();
}
public void bird()
{
birdSpeech();
}
public void birdSpeech()
{
Console.WriteLine("Chirp Chirp");
}
}
Could do something like this
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var p = new Program();
p.bird(p);
}
public void bird(Program program)
{
birdSpeech();
}
public void birdSpeech()
{
Console.WriteLine("Chirp Chirp");
}
}
I am trying to add webapi (owin.selfhosting) support to existing C# console app and I have problem with callbacks from the controller. Essentially I need to call a function as a reaction to the http request. I think it's possible with delegates/events, but so far no success.
Update:
Using static event seems to work, I used a standard pattern as described in this video (https://www.youtube.com/watch?v=jQgwEsJISy0) and adding a static keyword before event declaration. But mixing static delegate with non static subscriber probably is not the best practice.
Code sample :
//appcontroller.cs
public class AppController : ApiController
{ public delegate void EventHandler(object source, EventArgs args);
public static event EventHandler EventRecived;
protected virtual void OnEventRecived(string arg)
{
if( EventRecived != null)
{
EventRecived(this, arg);
}
}
[Route("api/{arg}")]
public void GetFoo(string arg)
{
/*
*
*/
OnEventRecived();
}
}
//program.cs
class Program
{ static void Main(string[] args)
{ WebApp.Start<Startup>(url: baseAddress);
SomeClass obj = new SomeClass();
AppController.EventHandler+=obj.OnRecivedEvent;
while (true)
{ //do work
}
}
}
class SomeClass
{ public SomeClass() {}
public void OnRecivedEvent(object sender, EventArgs e)
{
Foo(e);
}
public void Foo(string arg)
{
//do something
Console.WriteLine("request of "+arg);
}
}
Example for http get request to http://localhost:8080/api/holy_grail
Console output >>request of holy_grail
Assume I have a code:
class Module1 {
public static void Main(string[] args) {
Module1.level1();
}
public static void level1() {
Module1.level2();
}
public static void level2() {
Module2.level1();
}
}
[DetectWhenFlowExitsClass] // <-- note aspect
class Module2 {
public static void level1() {
Module2.level2();
}
public static void level2() {
Module2.level3();
}
public static void level3() {
throw new SystemException("oops");
}
}
After calling Main() I get a stacktrace:
Unhandled Exception: System.SystemException: oops
at Test.Module2.level3()
at Test.Module2.level2()
at Test.Module2.level1()
at Test.Module1.level2()
at Test.Module1.level1()
at Test.Module1.Main(String[] args)
Question
How to write aspect which detects moment when "control flow" exits code of class Module2?
That is, when Test.Module2.level1() finishes its work [here, due to exception].
Exist any shortcuts for this in PostSharp?
The most basic way would be to use OnMethodBoundaryAspect, which allows you to handle the method entry and method exit advices. You will need to count number of method of each particular class on the stack and when this count goes from 1 to 0, the control is leaving methods of the aspected class.
Here is the sample aspect code:
[Serializable]
public class DetectWhenFlowExitsClass : OnMethodBoundaryAspect
{
[ThreadStatic] private static Dictionary<Type, int> stackCounters;
private Type declaringType;
public override bool CompileTimeValidate(MethodBase method)
{
declaringType = method.DeclaringType;
return true;
}
private void EnsureStackCounters()
{
if (stackCounters == null)
stackCounters = new Dictionary<Type, int>();
}
public override void OnEntry(MethodExecutionArgs args)
{
EnsureStackCounters();
int counter;
stackCounters.TryGetValue(declaringType, out counter);
stackCounters[declaringType] = ++counter;
}
public override void OnExit(MethodExecutionArgs args)
{
EnsureStackCounters();
int counter;
stackCounters.TryGetValue(declaringType, out counter);
stackCounters[declaringType] = --counter;
if (counter == 0)
Console.WriteLine("Control leaving class {0}", declaringType.Name);
}
}
You will probably need to tinker with this aspect implementation a bit, but it works in basic situations.
I have an application. During the debugging, I log the important information to file or interactive interface.
Here is the example:
You see the first line log information doesn't have a thread name. I want to add a name. But where?
public static void Start()
{
lock (SyncVar)
{
if (State == State.Stopped)
{
s_State = State.Starting;
ThreadStart ts = new ThreadStart(MainCode);
s_MainCodeThread = new Thread(ts);
s_MainCodeThread.Name = "IvrApplication";
s_MainCodeThread.Start();
Log.Write("IvrApplication Starting...");
}
And....
public static void MainCode()
{
try
{
s_WorkingFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Log.Write("IvrApplication::MainCode() Starting...");
// Start Other Threads...
try
{
As for Log, we have
private static Log s_Log;
public static Log Log
{
get { return s_Log; }
}
Actually Log is from a dll
Here is the partial metadata.
namespace VoiceElements.Common
{
public class Log
{
[ThreadStatic]
public static string Identifier1;
[ThreadStatic]
public static string Identifier2;
public int LogLevel;
public Log(string logname);
public bool AlwaysExpanded { get; set; }
public event MessageLogged MessageLogged;
public void CloseLog();
public void Write(string LogEntry);
You just need to name the current thread:
Thread.CurrentThread.Name = "myThread";
That first log message is output by the application's default thread. You should be able to set that:
Thread.CurrentThread.Name = "SomeName";
Make sure to make that call before Log.Write("IvrApplication Starting...");.
You should rename the thread that executes your MainCode method:
public static void MainCode()
{
//SET A NAME HERE
Thread.CurrentThread.Name = "Main thread"
try
{
s_WorkingFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Log.Write("IvrApplication::MainCode() Starting...");
// Start Other Threads...
try
{
So here is my code:
class Program
{
static DispatchClass dc;
[STAThread]
static void Main(string[] args)
{
dc = new DispatchClass();
Thread th = new Thread(AccessDC);
th.Start();
Console.ReadKey();
}
private delegate void AccessDCDelegate(object state);
static private void AccessDC(object state)
{
if(dc.Dispatcher.CheckAccess())
dc.Print("hello");
else
dc.Dispatcher.Invoke(new AccessDCDelegate(AccessDC));
}
}
public class DispatchClass : DispatcherObject
{
public void Print(string str)
{
Console.WriteLine(str);
}
}
Now...the output I would expect from this is for the created thread to check the dispatcher access, see that it is on a different thread and then invoke AccessDC(...) on the original thread which then checks and sees that it is on the correct thread and calls dc.Print(...).
What actually happens is it gets to CheckAccess() and correctly sees that it isn't on the correct thread, then calls Invoke(...) and stops there.
Any insight into how Dispatchers work would be greatly appreciated.
Thanks.
The dispatcher requires a message pump, console apps do not have a message pump by default. Try running this as a GUI application instead - that will have a message pump.
CheckAccess verified that your CurrentThread DispatchClass is the current thread so it returned to you False. which is quite normal.
In this snippet of code
dc.Dispatcher.Invoke(new AccessDCDelegate(AccessDC));
You have a problem with arguments that's all.
this snippet of code works :
public partial class MainWindow : Window
{
static DispatchClass dc;
public MainWindow()
{
InitializeComponent();
dc = new DispatchClass();
Thread th = new Thread(AccessDC);
th.Start();
}
private delegate void AccessDCDelegate(object state);
static private void AccessDC(object state)
{
if (dc.Dispatcher.CheckAccess())
dc.Print("hello");
else
dc.Dispatcher.BeginInvoke(new Action(()=> AccessDC(null)));
}
}
public class DispatchClass : DispatcherObject
{
public void Print(string str)
{
MessageBox.Show(str);
}
}