WCF Named Pipes across the user session on same machine. Possible? - c#

Requirement
I am trying to create a "Single Instance" winforms app with args to be passed if second instance invoked. I hope Mutex will not work like this. I have made a WCF pipe on the winform app so that if another instance came, it will be notified to Main Instance with the required args which I will process the args on the Main Instance as required and second instance closed after notifying.
Issue:
The above code seems to be working fine, problem arises when it comes to multiple user session, When I logon to the machine as "User A" and opens my app, it opens up the app (Main instance). At the same time, if another user logon say "User B" and tries to open up the app, IT HAPPILY OPENS UP :(
Code:
Here is my code for single instance with WCF.
public static class SingleInstanceManager
{
/// <summary>
/// Raised when another instance attempts to start up.
/// </summary>
public static event StartupEventHandler OtherInstanceStarted;
/// <summary>
/// Checks to see if this instance is the first instance running on this machine. If it is not, this method will
/// send the main instance this instance's startup information.
/// </summary>
/// <param name="guid">The application's unique identifier.</param>
/// <returns>True if this instance is the main instance.</returns>
public static bool VerifySingleInstance(Guid guid)
{
if (!AttemptPublishService(guid))
{
NotifyMainInstance(guid);
return false;
}
return true;
}
/// <summary>
/// Attempts to publish the service.
/// </summary>
/// <param name="guid">The application's unique identifier.</param>
/// <returns>True if the service was published successfully.</returns>
private static bool AttemptPublishService(Guid guid)
{
try
{
ServiceHost serviceHost = new ServiceHost(typeof(SingleInstance));
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
serviceHost.AddServiceEndpoint(typeof(ISingleInstance), binding, CreateAddress(guid));
serviceHost.Open();
return true;
}
catch
{
return false;
}
}
/// <summary>
/// Notifies the main instance that this instance is attempting to start up.
/// </summary>
/// <param name="guid">The application's unique identifier.</param>
private static void NotifyMainInstance(Guid guid)
{
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
EndpointAddress remoteAddress = new EndpointAddress(CreateAddress(guid));
using (ChannelFactory<ISingleInstance> factory = new ChannelFactory<ISingleInstance>(binding, remoteAddress))
{
ISingleInstance singleInstance = factory.CreateChannel();
singleInstance.NotifyMainInstance(Environment.GetCommandLineArgs());
}
}
/// <summary>
/// Creates an address to publish/contact the service at based on a globally unique identifier.
/// </summary>
/// <param name="guid">The identifier for the application.</param>
/// <returns>The address to publish/contact the service.</returns>
private static string CreateAddress(Guid guid)
{
return string.Format(CultureInfo.CurrentCulture, "net.pipe://localhost/{0}", guid);
}
/// <summary>
/// The interface that describes the single instance service.
/// </summary>
[ServiceContract]
private interface ISingleInstance
{
/// <summary>
/// Notifies the main instance that another instance of the application attempted to start.
/// </summary>
/// <param name="args">The other instance's command-line arguments.</param>
[OperationContract]
void NotifyMainInstance(string[] args);
}
/// <summary>
/// The implementation of the single instance service interface.
/// </summary>
private class SingleInstance : ISingleInstance
{
/// <summary>
/// Notifies the main instance that another instance of the application attempted to start.
/// </summary>
/// <param name="args">The other instance's command-line arguments.</param>
public void NotifyMainInstance(string[] args)
{
if (OtherInstanceStarted != null)
{
Type type = typeof(StartupEventArgs);
ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
StartupEventArgs e = (StartupEventArgs)constructor.Invoke(null);
FieldInfo argsField = type.GetField("_args", BindingFlags.Instance | BindingFlags.NonPublic);
Debug.Assert(argsField != null);
argsField.SetValue(e, args);
OtherInstanceStarted(null, e);
}
}
}
}
On the Winforms Main:
static void Main()
{
//bool isSingle;
//var mut = new Mutex(true, "MarketFeeder", out isSingle);
var applicationId = new Guid("08f21b4e-86d7-4ddf-abcb-9a72cd2bbd4f");
if (SingleInstanceManager.VerifySingleInstance(applicationId))
{
SingleInstanceManager.OtherInstanceStarted += OnOtherInstanceStarted;
// Start the application
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
main = new MainForm();
System.Windows.Forms.Application.Run(main);
}
}
Help needed on
Is there a way to communicate via Namedpipe across the users on same machine?, I don't want to go for "Windows service" for my requirement which I feel over kill for my requirement.
Already went though following links but no luck. Also they are too old I feel we have better solution for this in recent times. I hope there are some devs like me who are still working on Windows applications :P
Isolated Named Pipes in Terminal Server Sessions

Related

Moq - Create mocked instance for constructor injected object

Question
I want to create a unit test for Credentials class that verifies the password for a given credentials after executing Calculate() method it its equal to the password calculated by an object that implements IPasswordCalculator interface.
Actually, the mock object that I created returns string.Empty value when calls Calculate(ICredentials) method, instead of Pa$$w0rd, that would be the desired return.
Then...
How I can implement this test without having to manually create a stub class?
How I can define the callback method on mock object to always return Pa$$w0rd?
Thanks in advance.
Code
IPasswordCalculator interface
/// <summary>
/// The password calculator interface.
/// </summary>
public interface IPasswordCalculator
{
/// <summary>
/// Calculates the user password using
/// <paramref name="credentials"/> instance.
/// </summary>
/// <param name="credentials">
/// <see cref="ICredentials"/> to perform the calculation.
/// </param>
void Calculate(ICredentials credentials);
}
ICredentials interface
/// <summary>
/// The Credentials interface.
/// </summary>
public interface ICredentials
{
/// <summary>
/// Gets or sets the user password.
/// </summary>
string Password { get; set; }
/// <summary>
/// Gets the user name.
/// </summary>
string Username { get; }
/// <summary>
/// Calculates the password.
/// </summary>
void Calculate();
}
Credentials implementation
/// <summary>
/// User credentials.
/// </summary>
public sealed class Credentials : ICredentials
{
/// <summary>
/// Initializes a new instance of the <see cref="Credentials" /> class.
/// </summary>
/// <param name="passwordCalculator">
/// The credentials calculator.
/// </param>
/// <param name="username">
/// The user name.
/// </param>
public Credentials(IPasswordCalculator passwordCalculator, string username)
{
this.Calculator = passwordCalculator;
this.Username = username;
this.Password = string.Empty;
}
/// <summary>
/// Calculates the password.
/// </summary>
public void Calculate()
{
if (null != this.Calculator)
{
this.Calculator.Calculate(this);
}
}
}
Test
/// <summary>
/// Calculate should set password value expected using calculator.
/// </summary>
[TestMethod]
public void CalculateShouldSetPasswordValueExpectedUsingCalculator()
{
ICredentials credentials = null;
var repo = new MockRepository(MockBehavior.Default);
var mock = repo.Create<IPasswordCalculator>();
mock.Setup(x => x.Calculate(credentials))
.Callback(() => { credentials.Password = "Pa$$w0rd"; });
IPasswordCalculator calculator = mock.Object;
credentials = new Credentials(calculator, "Me");
credentials.Calculate();
Assert.AreEqual("Pa$$w0rd", credentials.Password); // Fail
}
You need to setup your mock in the following way
mock.Setup(x => x.Calculate(It.IsAny<ICredentials>()))
.Callback((ICredentials c) => { c.Password = "Pa$$w0rd"; });
Thus you tell it "whatever ICredentials you get as the parameter of the Calculate method, set its Password to 'Pa$$word'"
I think you need to initialize the credentials variable before the call to mock.Setup(). With your code, Moq expects a call credentials.Calculate(null).

WCF call to "get" datamember in contract returns null

I have an operation contract in my service contract called
Schedule[] GetScheduleObjects();
I have a datameber in that operation contract called "Tasks" that returns a list of sub objects.
[DataMember()]
public Task[] Tasks
The issues is when the operation contract is called the method executes but the "get" of "Tasks" occurs twice. The first time it contains valid runtime instances, the second time it is null which causes a serialization exception. This happens despite only one call to the service. The binding is a tcp connection using a duplex proxy. Ideas?????
The Datacontract
[DataContract()]
public class Schedule
{
public Schedule(string name)
{
this.Name = name;
}
[DataMember()]
public string Name { get; private set; }
[DataMember()]
public bool Running { get; set; }
/// <summary>
/// Schedule Task is a DataMember object, do not modify
/// </summary>
[DataMember()]
public Task[] Tasks
{
get { return _Tasks.ToArray(); }
}
private List<Task> _Tasks = new List<Task>();
///<summary>
/// Use this property to add objects
///</summary>
public List<Task> ScheduleTasks
{
get { return _Tasks; }
}
}
The service contract
[ServiceContract(CallbackContract = typeof(ISummitDashboardCallbackContract))]
public interface ISchedulerContract : ISummitDashboardContract
{
/// <summary>
/// Sets the named schedule into "run" mode
/// </summary>
/// <param name="scheduleName"></param>
/// <returns></returns>
[OperationContract()]
void StartSchedule(string scheduleName);
/// <summary>
/// Pauses the currently running schedule
/// </summary>
/// <param name="scheduleName"></param>
[OperationContract()]
void PauseSchedule(string scheduleName);
/// <summary>
/// Removes the named schedule from "run" mode
/// </summary>
/// <param name="scheduleName"></param>
/// <returns></returns>
[OperationContract()]
void StopSchedule(string scheduleName);
/// <summary>
/// Flips the "active" state of the task with the named id
/// </summary>
/// <param name="scheduleName"></param>
/// <param name="Id"></param>
[OperationContract()]
void ToggleTaskState(string scheduleName, string Id);
/// <summary>
/// Flips the "active" state of the action with the named id
/// </summary>
/// <param name="scheduleName"></param>
/// <param name="Id"></param>
/// <returns></returns>
[OperationContract()]
void ToggleActionState(string scheduleName, string Id);
/// <summary>
/// Returns the information to build the tree list in the dashboard
/// </summary>
/// <returns></returns>
[OperationContract()]
Schedule[] GetScheduleObjects();
/// <summary>
/// Returns the events of the scheduler
/// </summary>
/// <returns></returns>
[OperationContract()]
SchedulerEvent[] GetSchedulerEvents(int startIndex, int count, int eventLogEntryType);
}
You'll need to add a setter to property Tasks, and you'll also need to increase the visibility of Name to at least protected - WCF will need to use these in order to deserialize objects of this class.
As a secondary issue, if a client generates a proxy (e.g. with Add Service Reference or via SvcUtil.exe), the 'code behind' Tasks (i.e. return _Tasks.ToArray(); which is coupled to ScheduledTasks) will be lost, and the client will instead just get a simple automatic backing property to property Tasks (with the collection class selected during the proxy generation). This second issue won't however happen however if you share type.

How to use events and delegate to send data between forms?

I need to create a Windows Form application that able to send data and to receive data from another Form instance. what mean, the Form is a publisher and a subscriber, both of them.
Unfortunately, I was sick that day, and I couldn't be in the lecture that day.
I'll explain again:
I have a small chat Form,
who have: new Instance button, received messages, and send message.
as you can see right below:
When I send a message, it will be shown in the "Recieved" textbox of ALL INSTANCES.
I guess that I need to use delegates and events.
How to do so? thanks!!
Here's a quick solution.. Let me know if you have any questions or if you find the comments confusing..
Here's the Form class (code behind). Notice that once the form is instantiated, it "subscribes" to an event by "wiring" an event handler to the HandleMessage event inside the Message class. Within the Form class, this is where the ListView's item collection is populated.
Whenever the New Form button is clicked, the same Form get's created and displayed (this allows for code re-use, since the same logic will be exactly the same for all instances of the Form)
public partial class Form1 : Form
{
Messages _messages = Messages.Instance; // Singleton reference to the Messages class. This contains the shared event
// and messages list.
/// <summary>
/// Initializes a new instance of the <see cref="Form1"/> class.
/// </summary>
public Form1()
{
InitializeComponent();
// Subscribe to the message event. This will allow the form to be notified whenever there's a new message.
//
_messages.HandleMessage += new EventHandler(OnHandleMessage);
// If there any existing messages that other forms have sent, populate list with them.
//
foreach (var messages in _messages.CurrentMessages)
{
listView1.Items.Add(messages);
}
}
/// <summary>
/// Handles the Click event of the buttonNewForm control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private void buttonNewForm_Click(object sender, EventArgs e)
{
// Create a new form to display..
//
var newForm = new Form1();
newForm.Show();
}
/// <summary>
/// Handles the Click event of the buttonSend control. Adds a new message to the "central" message list.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private void buttonSend_Click(object sender, EventArgs e)
{
string message = String.Format("{0} -- {1}", DateTime.UtcNow.ToLongTimeString(), textBox1.Text);
textBox1.Clear();
_messages.AddMessage(message);
}
/// <summary>
/// Called when [handle message].
/// This is called whenever a new message has been added to the "central" list.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
public void OnHandleMessage(object sender, EventArgs args)
{
var messageEvent = args as MessageEventArgs;
if (messageEvent != null)
{
string message = messageEvent.Message;
listView1.Items.Add(message);
}
}
}
Here's a Messages class that I created to handle a "central" list of messages that are sent between Forms. The Messages class is a singleton (meaning, it can be instantiated only once), which allow one list to be persisted throughout all instances of a Form. All Forms will share the same list, and get notified whenever a list has been updated. As you can see, the "HandleMessage" event is the Event that each Form will subscribe to whenever it has been created/shown.
If you take a look at the NotifyNewMessage function, this is called by the Messages class to notify the subscribes that there was a change. Since EventArgs are used to pass data to the subscribers, I've created a special EventArgs to pass the newly added messages to all subscribers.
class Messages
{
private List<string> _messages = new List<string>();
private static readonly Messages _instance = new Messages();
public event EventHandler HandleMessage;
/// <summary>
/// Prevents a default instance of the <see cref="Messages"/> class from being created.
/// </summary>
private Messages()
{
}
/// <summary>
/// Gets the instance of the class.
/// </summary>
public static Messages Instance
{
get
{
return _instance;
}
}
/// <summary>
/// Gets the current messages list.
/// </summary>
public List<string> CurrentMessages
{
get
{
return _messages;
}
}
/// <summary>
/// Notifies any of the subscribers that a new message has been received.
/// </summary>
/// <param name="message">The message.</param>
public void NotifyNewMessage(string message)
{
EventHandler handler = HandleMessage;
if (handler != null)
{
// This will call the any form that is currently "wired" to the event, notifying them
// of the new message.
handler(this, new MessageEventArgs(message));
}
}
/// <summary>
/// Adds a new messages to the "central" list
/// </summary>
/// <param name="message">The message.</param>
public void AddMessage(string message)
{
_messages.Add(message);
NotifyNewMessage(message);
}
}
/// <summary>
/// Special Event Args used to pass the message data to the subscribers.
/// </summary>
class MessageEventArgs : EventArgs
{
private string _message = string.Empty;
public MessageEventArgs(string message)
{
_message = message;
}
public String Message
{
get
{
return _message;
}
}
}
Also.. in order for the messages to be "displayed" correctly, don't forget the set the "View" property of the ListView control to "List". An easier (and preferred way) would simply be using the ObservableCollection list type, which already provides an event you can subscribe to.
Hope this helps.

add-in for visual studio 2010 compile error Connect class

Here:
Is there a way to specify outlining defaults in Visual Studio 2008 so that a file opens up with members collapsed by default?
..I could find an example for programming addins.. but unfortunately it doesnt compile :-(
Error 1
'CollapsedMembers.Connect' does not contain a definition for
'_openHandler' and no extension method '_openHandler' accepting a
first argument of type 'CollapsedMembers.Connect' could be found
(are you missing a using directive or an assembly reference?)
D:\CollapsedMembers\Connect.cs 77 18 CollapsedMembers
In fact there is no _openHandler there.. I have already tried all the .NET Framework versions but had unfortunately no success.
In OnOpenHandler.cs I have the OnOpenHandler implemented:
namespace CollapsedMembers
{
internal class OnOpenHandler
{
DTE2 _application = null;
EnvDTE.Events events = null;
EnvDTE.DocumentEvents docEvents = null;
... and so on...
can anyone help please?
[Edit:] Connect.cs is like following:
using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
namespace CollapsedMembers
{
/// <summary>The object for implementing an Add-in.</summary>
/// <seealso class='IDTExtensibility2' />
public class Connect : IDTExtensibility2
{
/// <summary>Implements the constructor for the Add-in object. Place your initialization code within this method.</summary>
public Connect()
{
}
/// <summary>Implements the OnConnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being loaded.</summary>
/// <param term='application'>Root object of the host application.</param>
/// <param term='connectMode'>Describes how the Add-in is being loaded.</param>
/// <param term='addInInst'>Object representing this Add-in.</param>
/// <seealso class='IDTExtensibility2' />
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
switch (connectMode)
{
case ext_ConnectMode.ext_cm_UISetup:
case ext_ConnectMode.ext_cm_Startup:
//Do nothing OnStartup will be called once IDE is initialised.
break;
case ext_ConnectMode.ext_cm_AfterStartup:
//The addin was started post startup so we need to call its initialisation manually
InitialiseHandlers();
break;
}
}
/// <summary>Implements the OnDisconnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being unloaded.</summary>
/// <param term='disconnectMode'>Describes how the Add-in is being unloaded.</param>
/// <param term='custom'>Array of parameters that are host application specific.</param>
/// <seealso class='IDTExtensibility2' />
public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
{
}
/// <summary>Implements the OnAddInsUpdate method of the IDTExtensibility2 interface. Receives notification when the collection of Add-ins has changed.</summary>
/// <param term='custom'>Array of parameters that are host application specific.</param>
/// <seealso class='IDTExtensibility2' />
public void OnAddInsUpdate(ref Array custom)
{
}
/// <summary>Implements the OnStartupComplete method of the IDTExtensibility2 interface. Receives notification that the host application has completed loading.</summary>
/// <param term='custom'>Array of parameters that are host application specific.</param>
/// <seealso class='IDTExtensibility2' />
public void OnStartupComplete(ref Array custom)
{
InitialiseHandlers();
}
/// <summary>Implements the OnBeginShutdown method of the IDTExtensibility2 interface. Receives notification that the host application is being unloaded.</summary>
/// <param term='custom'>Array of parameters that are host application specific.</param>
/// <seealso class='IDTExtensibility2' />
public void OnBeginShutdown(ref Array custom)
{
}
private DTE2 _applicationObject;
private AddIn _addInInstance;
private void InitialiseHandlers()
{
this._openHandler = new OnOpenHandler(_applicationObject);
}
}
}
_openHandler is a member of Connect class and it isn't defined, and you are using it the
private void InitialiseHandlers()
{
this._openHandler = new OnOpenHandler(_applicationObject);
}
method you copied. You need to define a OnOpenHandler _openHandler member for Connect class.

Return a string from a Service already running using Remoting

im trying to use .Net Remoting to get a value of a variable that i use in a thread of an windows service.
TcpChannel tcpChannel = new TcpChannel(9998);
ChannelServices.RegisterChannel(tcpChannel, false);
Type commonInterfaceType = typeof(MyNameSpace.Core.Engine);
RemotingConfiguration.RegisterWellKnownServiceType(commonInterfaceType,
"CopyFilePercentage",
WellKnownObjectMode.SingleCall);
myEngine = Engine.EngineInstance;
myEngine.Start();
But it seams that every time that i use the Client to get that value, a new thread is created returning an empty string.
Any idea why is this happening or am I doing something wrong?
Thanks in advance,
Miguel de Sousa
WellKnownObjectMode.SingleCall creates a new instance of your class for each call. try WellKnownObjectMode.Singleton
EDIT
Maybe you should read about client activated objects. Turn your singleton object to a class factory and return a new instance of a real worker class(ofcourse inheriting from MarshalByRefObject) which will be used by the client.
so your client will be something like this
var worker = client.GetWorkerClass();
worker.GetSomeData();
and you will have one server object per connection (this may not be the correct terminology).
well i just used a Global Variable Class not really what I wanted but does the job.
/// <summary>
/// Contains global variables for project.
/// </summary>
public static class GlobalVar
{
/// <summary>
/// Global variable that is constant.
/// </summary>
public const string GlobalString = "Important Text";
/// <summary>
/// Static value protected by access routine.
/// </summary>
static int _globalValue;
/// <summary>
/// Access routine for global variable.
/// </summary>
public static int GlobalValue
{
get
{
return _globalValue;
}
set
{
_globalValue = value;
}
}
/// <summary>
/// Global static field.
/// </summary>
public static bool GlobalBoolean;
}

Categories