using namespace System;
using namespace System::Threading;
using namespace System::Security;
using namespace System::Collections;
using namespace System::Security::Permissions;
using namespace System::Runtime::Serialization;
using namespace System::Runtime::Remoting::Messaging;
// One means of communicating between client and server is
// to use the CallContext class. Calling CallContext effectively puts the data
// in a thread local store. This means that the information is available
// to that thread or logical thread (across application domains) only.
[Serializable]
public ref class CallContextString: public ILogicalThreadAffinative
{
private:
String^ _str;
public:
CallContextString( String^ str )
{
_str = str;
Console::WriteLine( "A CallContextString has been created." );
}
virtual String^ ToString() override
{
return _str;
}
};
public ref class ContextBoundType: public ContextBoundObject
{
private:
DateTime starttime;
public:
ContextBoundType()
{
Console::WriteLine( "An instance of ContextBoundType has been created." );
starttime = DateTime::Now;
}
[SecurityPermissionAttribute(SecurityAction::Demand, Flags = SecurityPermissionFlag::Infrastructure)]
DateTime GetServerTime()
{
Console::WriteLine( "The time requested by a client." );
// This call overwrites the client's
// CallContextString.
CallContext::SetData( "ServerThreadData", gcnew CallContextString( "This is the server side replacement string." ) );
return DateTime::Now;
}
};
// Execute the Demand.
void DemandPermission()
{
try
{
Console::WriteLine( "\nIn thread {0} executing a Demand for " +
"FileDialogPermission.", Thread::CurrentThread->Name );
(gcnew FileDialogPermission( FileDialogPermissionAccess::OpenSave ))->Demand();
Console::WriteLine( "Successfully demanded FileDialogPermission." );
}
catch ( Exception^ e )
{
Console::WriteLine("Demand for FileDialogPermission failed with {0}.", e->GetType());
}
};
void ExecutionContextMethods()
{
// Generate a call context for this thread.
ContextBoundType^ cBT = gcnew ContextBoundType;
cBT->GetServerTime();
ExecutionContext ^ eC1 = ExecutionContext::Capture();
ExecutionContext ^ eC2 = eC1->CreateCopy();
Console::WriteLine( "\nThe hash code for the first execution context is: {0}",
eC1->GetHashCode() );
// Create a SerializationInfo object to be used for getting the object data.
SerializationInfo^ sI = gcnew SerializationInfo( ExecutionContext::typeid, gcnew FormatterConverter );
eC1->GetObjectData( sI, StreamingContext(StreamingContextStates::All) );
LogicalCallContext^ lCC = dynamic_cast<LogicalCallContext^>(sI->GetValue( "LogicalCallContext", LogicalCallContext::typeid ));
// The logical call context object should contain the previously created call context.
Console::WriteLine( "Is the logical call context information available? {0}", lCC->HasInfo );
};
void CallbackInContext(Object^ state)
{
// The state is not used in this example.
DemandPermission();
};
int main()
{
try
{
Thread::CurrentThread->Name = "Main";
Console::WriteLine( "Executing Main() in the primary application thread (\"{0}\").",
Thread::CurrentThread->Name );
FileDialogPermission^ fdp = gcnew FileDialogPermission( FileDialogPermissionAccess::OpenSave );
fdp->Deny();
// Capture the execution context containing the Deny.
ExecutionContext ^ eC = ExecutionContext::Capture();
// Suppress the flow of the execution context across threads.
Console::WriteLine("Suppress the flow of the execution context.");
AsyncFlowControl aFC = ExecutionContext::SuppressFlow();
Console::WriteLine( "Is the flow suppressed? {0}",
ExecutionContext::IsFlowSuppressed() );
Thread^ t1 = gcnew Thread( gcnew ThreadStart( &DemandPermission ) );
t1->Name = "T1";
t1->Start();
t1->Join();
Console::WriteLine( "Restore the flow." );
aFC.Undo();
Console::WriteLine( "Is the flow suppressed? {0}", ExecutionContext::IsFlowSuppressed() );
Thread^ t2 = gcnew Thread( gcnew ThreadStart( &DemandPermission ) );
t2->Name = "T2";
t2->Start();
t2->Join();
// Remove the Deny.
CodeAccessPermission::RevertDeny();
// Capture the context that does not contain the Deny.
ExecutionContext ^ eC2 = ExecutionContext::Capture();
// Show that the Deny is no longer present.
Thread^ t3 = gcnew Thread( gcnew ThreadStart( &DemandPermission ) );
t3->Name = "T3";
t3->Start();
t3->Join();
// Use the Run method to execute DemandPermission in
// the captured context, where Deny is active. The
// demand fails.
ContextCallback^ callback = gcnew ContextCallback(&CallbackInContext);
ExecutionContext::Run(eC, callback, nullptr);
Console::WriteLine();
// Demonstrate the execution context methods.
ExecutionContextMethods();
Console::WriteLine( "Demo is complete, press Enter to exit." );
Console::Read();
}
catch ( Exception^ e )
{
Console::WriteLine( e->Message );
}
}
/* This code produces output similar to the following:
Executing Main() in the primary application thread ("Main").
Suppress the flow of the execution context.
Is the flow suppressed? True
In thread T1 executing a Demand for FileDialogPermission.
Successfully demanded FileDialogPermission.
Restore the flow.
Is the flow suppressed? False
In thread T2 executing a Demand for FileDialogPermission.
Demand for FileDialogPermission failed with System.Security.SecurityException.
In thread T3 executing a Demand for FileDialogPermission.
Successfully demanded FileDialogPermission.
In thread Main executing a Demand for FileDialogPermission.
Demand for FileDialogPermission failed with System.Security.SecurityException.
An instance of ContextBoundType has been created.
The time requested by a client.
A CallContextString has been created.
The hash code for the first execution context is: 58225482
Is the logical call context information available? True
Demo is complete, press Enter to exit.
*/