I'm just trying to do a simple event handler on a string variable, so that if the string changes, it will do a Console.WriteLine (using the new Reactive library from MS (Rx))
The issue that I have is that it will display the first bit when I instantiate the class ("RandomGuid : Mine?"), but after that, none of the stuff I change afterwards spits anything out to the console.
I went through the HOL from the MS website, but it goes straight from defining the Observable into reading values from a textbox, when all I want to do is watch whether a string was changed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MynahBirds
{
class Program
{
static void Main(string[] args)
{
List<Minah> minahs = new List<Minah>();
for (int i = 0; i < 10; i++) {
minahs.Add(new Minah());
}
foreach (var item in minahs) {
item.peers = minahs;
}
minahs.ForEach(m => m.s = Observable.Return<string>("Mine"));
minahs.ForEach(m => m.s = Observable.Return<string>("Whee"));
minahs.ForEach(m => m.s = Observable.Return<string>("Argh"));
Console.ReadLine();
}
}
class Minah
{
Guid Id;
public List<Minah> peers;
IDisposable subscription;
public IObservable<string> s = Observable.Return<string>("Mine?");
public Minah()
{
try {
this.Id = Guid.NewGuid();
subscription = s.Subscribe((string a) => {
Console.WriteLine("{0} : {1}", this.Id, a);
},
(Exception ex) => {
Console.WriteLine("Error {0} hit", ex.ToString());
},
() => { });
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
Console.ReadLine();
throw;
}
}
}
}
When you assign to m.s in the ForEach you are not updating the existing observable (which you have subscribed to) with a new value, instead you are creating new observables, which is what Observable.Return does. The code below does what I think you expect:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MynahBirds
{
class Program
{
static void Main(string[] args)
{
List<Minah> minahs = new List<Minah>();
for (int i = 0; i < 10; i++)
{
minahs.Add(new Minah());
}
foreach (var item in minahs)
{
item.peers = minahs;
}
minahs.ForEach(m => m.s.OnNext("Mine"));
minahs.ForEach(m => m.s.OnNext("Whee"));
minahs.ForEach(m => m.s.OnNext("Argh"));
Console.ReadLine();
}
}
class Minah
{
Guid Id;
public List<Minah> peers;
IDisposable subscription;
public ISubject<string> s = new Subject<string>();
public Minah()
{
try
{
this.Id = Guid.NewGuid();
subscription = s.Subscribe((string a) =>
{
Console.WriteLine("{0} : {1}", this.Id, a);
},
(Exception ex) =>
{
Console.WriteLine("Error {0} hit", ex.ToString());
},
() => { });
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
throw;
}
}
}
}
Instead of using Observable.Return<T>(), here I use a Subject, which is both an observer and an observable sequence. It updates all its subscriptions with each value it observes. So when OnNext is called on the subject, it is forwarded to all subscriptions.
If you need the initial value (Mine?) you can add s.OnNext("Mine?"); at the end of the Minah constructor.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Collections.Concurrent;
namespace MynahBirds
{
class Program
{
static void Main(string[] args)
{
ThreadPool.SetMaxThreads(100, 100);
ConcurrentBag<Minah> minahs = new ConcurrentBag<Minah>();
Stopwatch ti = new Stopwatch();
ti.Start();
Task.Factory.StartNew(() => {
for (int i = 1; i < 2501; i++) {
minahs.Add(new Minah(i));
};
});
Task.Factory.StartNew(() => {
for (int i = 1; i < 2501; i++) {
minahs.Add(new Minah(i));
};
});
Task.Factory.StartNew(() => {
for (int i = 1; i < 2501; i++) {
minahs.Add(new Minah(i));
};
});
Task.Factory.StartNew(() => {
for (int i = 1; i < 2501; i++) {
minahs.Add(new Minah(i));
};
});
Task.WaitAll();
string[] alpha = { "Alpha", "Bravo", "Charlie", "Delta", "Eagle", "Foxtrot", "Gulf", "Hotel" };
foreach (string s in alpha) {
Console.WriteLine(s);
Task.Factory.StartNew(() => minahs.AsParallel().ForAll(m => m.RepeatWord = s)).Wait();
}
minahs.AsParallel().ForAll(m => m.s.OnCompleted());
ti.Stop();
Console.WriteLine("{1} birds : {0} seconds", ti.Elapsed.TotalSeconds, minahs.Count);
Console.ReadLine();
}
}
class Minah
{
Guid Id;
IDisposable subscription;
public ISubject<string> s = new Subject<string>();
private string _RepeatWord;
public string RepeatWord
{
get
{
return _RepeatWord;
}
set
{
this.s.OnNext(value);
_RepeatWord = value;
}
}
public Minah(int i)
{
try {
this.Id = Guid.NewGuid();
subscription = s.Subscribe((string a) => {
Console.WriteLine("{0} : {1}", i, a);
},
(Exception ex) => {
Console.WriteLine("Error {0} hit", ex.ToString());
},
() => { /* Console.WriteLine("{0} : Completed", this.Id); */ });
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
Console.ReadLine();
throw;
}
}
}
}
This is what I ended up doing with help from Markus. More playing around with parallelism. Interestingly, if I remove the .Wait() from the end of the .ForAll(... RepeatWord = s), it will only do the last word in the sequence. I'm guessing that is a closure thing, but I'm not overly concerned about it.
Related
I want to optimize My server side speed and performance to manage clients, I think I have two way to mange them:
1.Create manually one thread per client connection
2.create SynchronizationContext per client (this will manage threads on background)
Suppose We have one million users connected:
The first way is faster but I don't know is optimize and better way to manage send/receive data from client or not?
What is your suggestion to make better performance and speed to manage all of clients without lags and hangs?
My example to test SynchronizationContext and multi thread on console:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SynchronizationContextForMethod
{
public class ServiceClass
{
public void Login(string name)
{
OperationContext<ClientInfo>.Current = new ClientInfo() { Name = name };
}
public string WhatIsMyName()
{
return OperationContext<ClientInfo>.Current.Name;
}
}
public class ClientInfo
{
public string Name { get; set; }
public string UserName { get; set; }
}
public class OperationContext<T>
{
static ConcurrentDictionary<SynchronizationContext, T> ContextByThread = new ConcurrentDictionary<SynchronizationContext, T>();
public static T Current
{
get
{
ContextByThread.TryGetValue(SynchronizationContext.Current, out T value);
return value;
}
set
{
ContextByThread.TryAdd(SynchronizationContext.Current, value);
}
}
public static void EncContext()
{
ContextByThread.TryRemove(SynchronizationContext.Current, out T value);
}
}
class Program
{
static List<SynchronizationContext> _contexts = new List<SynchronizationContext>();
static void Main(string[] args)
{
ThreadPool.GetMaxThreads(out int worker, out int ports);
ThreadPool.SetMaxThreads(int.MaxValue, int.MaxValue);
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
_contexts.Add(SynchronizationContext.Current);
var service = new ServiceClass();
for (int i = 0; i < 20; i++)
{
//PostWithNewThread((state) =>
PostNormally((state) =>
{
GC.Collect();
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
else
{
//no run ever
}
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
var name = state.ToString();
service.Login(name);
var isTrue = name == service.WhatIsMyName();
if (!isTrue)
{
//if false this is wrong code!
}
Console.WriteLine($"service login {name}: " + isTrue);
Thread.Sleep(5000);
Console.WriteLine($"service " + name + " finished");
OperationContext<ClientInfo>.EncContext();
}, "ali" + i);
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
//PostWithNewThread((state) =>
PostNormally((state) =>
{
GC.Collect();
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
else
{
//no run ever
}
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
var name = state.ToString();
service.Login(name);
var isTrue = name == service.WhatIsMyName();
if (!isTrue)
{
//if false this is wrong code!
}
Console.WriteLine($"service login {name}: " + isTrue);
Console.WriteLine($"service " + name + " finished");
OperationContext<ClientInfo>.EncContext();
}, "reza" + i);
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
//PostWithNewThread((state) =>
PostNormally((state) =>
{
GC.Collect();
if (SynchronizationContext.Current == null)
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
else
{
//no run ever
}
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
Thread.Sleep(2000);
var name = state.ToString();
service.Login(name);
var isTrue = name == service.WhatIsMyName();
if (!isTrue)
{
//if false this is wrong code!
}
Console.WriteLine($"service login {name}: " + (isTrue));
Console.WriteLine($"service " + name + " finished");
OperationContext<ClientInfo>.EncContext();
}, "hassan" + i);
}
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
while (true)
{
GC.Collect();
Thread.Sleep(1000);
Console.WriteLine("thread count : " + Process.GetCurrentProcess().Threads.Count);
}
}
public static void PostNormally(SendOrPostCallback run, object state)
{
SynchronizationContext.Current.Post(run, state);
}
public static void PostWithNewThread(SendOrPostCallback run, object state)
{
Thread thread = new Thread(() =>
{
run(state);
});
thread.IsBackground = true;
thread.Start();
}
}
}
I am programming a discord bot in Discord .NET 0.9 and I get a stack overflow error when I try to run it. The problem a occurs when I make a instance of my Program.cs in my Functions.cs
My Program.cs:
using System;
using System.Linq;
using Discord;
using Discord.Commands;
using System.IO;
using fatobg;
namespace fatobg
{
class Program
{
CommandManager cm = new CommandManager();
public static Program _instance = new Program();
static void Main(string[] args)
{
new Program().Start();
}
public DiscordClient _client;
public void Start()
{
Console.Title = "Matchmaking Discord BOT";
_client = new DiscordClient(x =>
{
x.AppName = "Gerry";
x.AppUrl = "www.google.com";
x.LogLevel = LogSeverity.Info;
x.LogHandler = Log;
});
_client.UsingCommands(x =>
{
x.PrefixChar = '?';
x.AllowMentionPrefix = true;
x.HelpMode = HelpMode.Public;
});
var token = "Changed";
cm.Commands(_client);
onJoin();
_client.ExecuteAndWait(async () =>
{
await _client.Connect(token, TokenType.Bot);
setGame(_client, "?help");
});
}
public void setGame(DiscordClient _client, string game)
{
_client.SetGame(game);
}
public void onJoin()
{
_client.UserJoined += async (s, e) =>
{
await e.Server.GetChannel(318558393759694849).SendMessage($":loudspeaker: | Everyone welcome {e.User.Mention} to the server!");
};
}
public void Log(Object sender, LogMessageEventArgs e)
{
Console.WriteLine($"[{e.Severity}] [{e.Source}] {e.Message}");
}
}
}
My CommandManager.cs:
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using Discord;
using System.Net.Http;
using Discord.Commands;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using System.IO;
using System.Threading;
using MySql.Data;
using MySql.Data.MySqlClient;
namespace fatobg
{
class CommandManager
{
public static CommandManager _instance = new CommandManager();
Functions function = new Functions();
public void Commands(DiscordClient _client)
{
var cService = _client.GetService<CommandService>();
cService.CreateCommand("say")
.Description("returns commands")
.Parameter("message", ParameterType.Unparsed)
.Do(async (e) =>
{
Message[] messageToDelete;
int deleteNumber = 1;
messageToDelete = await e.Channel.DownloadMessages(deleteNumber);
await e.Channel.DeleteMessages(messageToDelete);
var toReturn = $":envelope: | {e.GetArg("message")}";
await e.Channel.SendMessage(toReturn);
Console.WriteLine(toReturn);
});
cService.CreateCommand("updatedb")
.Description("updates database")
.Do(async (e) =>
{
Message[] messageToDelete; //deletes command
int deleteNumber = 1;
messageToDelete = await e.Channel.DownloadMessages(deleteNumber);
await e.Channel.DeleteMessages(messageToDelete);
try
{
if (e.User.ServerPermissions.Administrator)
{
foreach (User user in e.Server.Users)
{
if(!user.IsBot)
function.UpdateDB(user);
}
var toReturn = $":white_check_mark: | Done updateing the database. {e.User.Mention}";
await e.Channel.SendMessage(toReturn);
Console.WriteLine(toReturn);
}
else
{
var toReturn = $":exclamation: | Get out of here {e.User.Mention} you have no power over me!";
await e.Channel.SendMessage(toReturn);
Console.WriteLine(toReturn);
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex);
}
});
cService.CreateCommand("duo")
.Description("returns commands")
.Do(async (e) =>
{
Message[] messageToDelete;
int deleteNumber = 1;
messageToDelete = await e.Channel.DownloadMessages(deleteNumber);
await e.Channel.DeleteMessages(messageToDelete);
});
cService.CreateCommand("yamikage")
.Description("Animated gingy")
.Do(async (e) =>
{
Message[] messageToDelete;
int deleteNumber = 1;
messageToDelete = await e.Channel.DownloadMessages(deleteNumber);
await e.Channel.DeleteMessages(messageToDelete);
await e.Channel.SendFile("Gifs/gingy.gif");
Console.WriteLine("Send epic gingy meme");
});
}
}
}
My Functions.cs:
using Discord;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace fatobg
{
class Functions
{
Program main = new Program();
public void UpdateDB(User user)
{
if (File.Exists(#"D:\Databases\DiscordUsers\" + user.Id + ".duser"))
{
System.IO.File.Delete(#"D:\Databases\DiscordUsers\" + user.Id + ".duser");
string[] Data = { user.Name, Roles(user) };
System.IO.File.WriteAllLines(#"D:\Databases\DiscordUsers\" + user.Id + ".duser", Data);
}
else
{
string[] Data = { user.Name, Roles(user) };
System.IO.File.WriteAllLines(#"D:\Databases\DiscordUsers\" + user.Id + ".duser", Data);
}
}
public string Roles(User user)
{
string toreturn = string.Empty;
foreach (Role role in user.Roles)
{
if (role.Name!="Admin"||role.Name!="Mod"||role.Name!="#everyone")
{
toreturn += role.Name + "|";
}
}
return toreturn;
}
public string GetUsername(string uid)
{
if (File.Exists(#"D:\Databases\DiscordUsers\" + uid + ".duser"))
{
string[] Data = File.ReadAllLines(#"D:\Databases\DiscordUsers\" + uid + ".duser");
return Data[0];
}
else
{
return null;
}
}
public void AddToQueue(User user)
{
List<User> NA = new List<User>();
List<User> EU = new List<User>();
List<User> OC = new List<User>();
List<User> AS = new List<User>();
List<User> SA = new List<User>();
Server server = main._client.FindServers("Find A Team On Battlegrounds (Bot Testing)").FirstOrDefault();
User usr = server.FindUsers(user.Name).FirstOrDefault();
if (File.Exists(#"D:\Databases\Duo.queue"))
{
string[] UData = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach(String uid in UData)
{
User tempuser = user.Server.FindUsers(GetUsername(uid)).FirstOrDefault();
List<Role> roles = tempuser.Roles.ToList();
foreach(Role role in roles)
{
if (role.Name == "[NA]")
NA.Add(tempuser);
else if (role.Name == "[EU]")
EU.Add(tempuser);
else if (role.Name == "[OC]")
OC.Add(tempuser);
else if (role.Name == "[AS]")
AS.Add(tempuser);
else if (role.Name == "[SA]")
SA.Add(tempuser);
}
}
List<Role> uroles = usr.Roles.ToList();
foreach (Role role in uroles)
{
if (role.Name == "[NA]")
NA.Add(usr);
else if (role.Name == "[EU]")
EU.Add(usr);
else if (role.Name == "[OC]")
OC.Add(usr);
else if (role.Name == "[AS]")
AS.Add(usr);
else if (role.Name == "[SA]")
SA.Add(usr);
}
File.WriteAllLines(#"D:\Databases\Duo.queue", UData);
File.AppendAllText(#"D:\Databases\Duo.queue", usr.Id.ToString() + Environment.NewLine);
if (NA.Count == 2)
{
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for NA servers. {NA[0].Mention} and {NA[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if(id!=NA[0].Id.ToString()&&id!=NA[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
NA.Clear();
}
else if (EU.Count == 2){
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for EU servers. {EU[0].Mention} and {EU[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if (id!=EU[0].Id.ToString()&&id!=EU[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
EU.Clear();
}
else if (OC.Count == 2)
{
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for OC servers. {OC[0].Mention} and {OC[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if (id!=OC[0].Id.ToString()&&id!=OC[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
OC.Clear();
}
else if (AS.Count == 2)
{
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for AS servers. {AS[0].Mention} and {AS[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if (id != AS[0].Id.ToString() && id != AS[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
AS.Clear();
}
else if (SA.Count == 2)
{
server.GetChannel(319281246746312714).SendMessage($":exclamation: | A new team has been found for SA servers. {SA[0].Mention} and {SA[1].Mention} prepare to fight.");
string[] Data = System.IO.File.ReadAllLines(#"D:\Databases\Duo.queue");
System.IO.File.Delete(#"D:\Databases\Duo.queue");
foreach (String id in Data)
{
if (id != SA[0].Id.ToString()&&id!=SA[1].Id.ToString())
File.AppendAllText(#"D:\Databases\Duo.queue", id + Environment.NewLine);
}
SA.Clear();
}
}
else
{
File.AppendAllText(#"D:\Databases\Duo.queue", usr.Id.ToString() + Environment.NewLine);
}
}
}
}
This is what happens:
Instantiate Program;
Program instantiates CommandManager;
CommandManager instantiates Functions;
Functions instantiates Program;
Return to 1.
What you should do:
Pass along an instance of Program to CommandManager and Functions. In that way, you have no circular reference any more.
For example your Functions class should start with this:
class Functions
{
Program main;
public Functions(Program p)
{
this.main = p;
}
And your CommandManager:
class CommandManager
{
Program main;
Functions function;
public CommandManager(Program p)
{
this.main = p;
this.function = new Function(p);
}
I am using excel-DNA example as basis for this test.
I want excel to show my updated data in cell B1 every 1 second.
This works fine for about the first 5 secs, then I get a timer and the have to wait for function finish to see only the last value.
How do I force the update to be shown on the spreadsheet at each cycle of the loop?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExcelDna.Integration;
using System.Threading.Tasks;
using System.Diagnostics;
namespace BTPRTD
{
class Program
{
static void Main(string[] args)
{
}
}
public static class MyFunctions
{
public static MouseData MData;
[ExcelFunction(Description = "My first .NET function")]
public static string SayHello(string name)
{
//Debugger.Launch();
MData = new MouseData ();
Task.Factory.StartNew(() =>
{
ExcelAsyncUtil.QueueAsMacro(() =>
{
KeepWritingData();
});
});
return "Hello " + name;
}
public static void KeepWritingData()
{
var refB1 = new ExcelReference(0, 0, 1, 1, "Sheet1");
string dataTxt = "";
for (int i = 0; i < 100; i++)
{
try
{
MouseData .CurrentPriceData CPD = MData.GetCurrentPriceNT("White mouse");
dataTxt = CPD.AsString();
}
catch (Exception)
{
dataTxt = "Data Unavailable";
}
refB1.SetValue("Ding: " + i + " " + dataTxt);
System.Threading.Thread.Sleep(1000);
}
}
}
}
Excel supports a type of worksheet function called RealTimeData (RTD), which is what you should use for your scenario.
Follow the examples in the "Samples" GitHub repository. In special, take a look at the RtdClocks example that uses an Observable Timer:
public static class RtdClock
{
[ExcelFunction(Description = "Provides a ticking clock")]
public static object dnaRtdClock_Rx()
{
string functionName = "dnaRtdClock_Rx";
object paramInfo = null; // could be one parameter passed in directly, or an object array of all the parameters: new object[] {param1, param2}
return ObservableRtdUtil.Observe(functionName, paramInfo, () => GetObservableClock() );
}
static IObservable<string> GetObservableClock()
{
return Observable.Timer(dueTime: TimeSpan.Zero, period: TimeSpan.FromSeconds(1))
.Select(_ => DateTime.Now.ToString("HH:mm:ss"));
}
}
I have a failing testcase that depends on an external module.
I want to use Rhino Mock to generate a report on called functions.
I created a minimal example that illustrates my problem:
using NUnit.Framework;
using Rhino.Mocks;
using System;
namespace StackOverflow_namespace
{
public interface IUsefulService
{
object HiddenAmongManyCalls();
}
public class ThirdPartyBase
{
private int a = 42;
public ThirdPartyBase(IUsefulService service)
{
object liveFastDieYoung = service.HiddenAmongManyCalls();
liveFastDieYoung.Equals(a);
}
}
public class MyParty : ThirdPartyBase
{
public MyParty(IUsefulService service) : base(service)
{
}
}
[TestFixture]
class StackOverflow
{
[Test]
public void Hypothetical()
{
IUsefulService service = MockRepository.GenerateMock<IUsefulService>();
try
{
var party = new MyParty(service);
}
catch(Exception e)
{
string[] calls = MagicallyGetTheCallsThatWereMadeToTheMock();
foreach(var call in calls)
{
//with my visual studio testrunner for nunit 3 I can investigate stored console output
Console.WriteLine(call);
}
Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
}
}
private string[] MagicallyGetTheCallsThatWereMadeToTheMock()
{
return new[]
{
"This is where I am lost, I do not know how to get the calls from the repository."
};
}
}
}
I tried to find something online without success.
Do Rhino Mocks record all calls and can I access that list?
Edit:
An attempt to verify Expectations did not work since I am looking for calls I did not expect.
I could build a list of calls using GetArgumentsForCallsMadeOn. I can reflect on the Interface. I started on a method for that but I currently fail to see how I can convert a MethodInfo to an Action<T>.
private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
Type interfaceType = typeof(Interface);
List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
List<string> returnInfos = new List<string>();
StringBuilder callbuilder = new StringBuilder();
foreach (var property in interfaceType.GetProperties())
{
interfaceMethodInfos.Add(property.GetGetMethod());
interfaceMethodInfos.Add(property.GetSetMethod());
}
foreach (var method in interfaceType.GetMethods())
{
interfaceMethodInfos.Add(method);
}
foreach (var methodinfo in interfaceMethodInfos)
{
Action<Interface> magic = null; //convert methodinfo into action - still missing
var calls = rhinomock.GetArgumentsForCallsMadeOn(magic); //magic is currently null, here be crash
foreach (var call in calls)
{
bool more = false;
callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
foreach (var parameter in call)
{
if (more){ callbuilder.Append(", "); }
if (null == parameter) { callbuilder.Append("<null>"); }
else { callbuilder.Append(parameter.ToString()); }
more = true;
}
callbuilder.Append(')');
string callInfo = callbuilder.ToString();
returnInfos.Add(callInfo);
}
}
return returnInfos;
}
I was able to use reflection to get the output I wanted.
Here is the minimal example where the test fails and the output contains all method calls.
using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace StackOverflow_namespace
{
public interface IUsefulService
{
object HiddenAmongManyCalls();
string TestCall2(string arg1, int arg2);
string FULLACCESS { get; set; }
string READONLY { get; }
}
public class ThirdPartyBase
{
private int a = 42;
public ThirdPartyBase(IUsefulService service)
{
service.TestCall2("callA", 1);
service.TestCall2("callB", 1);
object liveFastDieYoung = service.HiddenAmongManyCalls();
service.TestCall2("callA", 2);
service.TestCall2("callB", 2);
var a = service.FULLACCESS;
var b = service.READONLY;
service.FULLACCESS = "some";
liveFastDieYoung.Equals(a);
}
}
public class MyParty : ThirdPartyBase
{
public MyParty(IUsefulService service) : base(service)
{
}
}
[TestFixture]
class StackOverflow
{
[Test]
public void Hypothetical()
{
IUsefulService service = MockRepository.GenerateMock<IUsefulService>();
try
{
var party = new MyParty(service);
}
catch (Exception e)
{
var calls = GetCallsList(service);
foreach (var call in calls)
{
//with my visual studio testrunner for nunit 3 I can investigate stored console output
Console.WriteLine(call);
}
Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
}
}
private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
Type interfaceType = typeof(Interface);
List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
List<string> returnInfos = new List<string>();
StringBuilder callbuilder = new StringBuilder();
foreach (var property in interfaceType.GetProperties())
{
AddMethodInfoIfValid(interfaceMethodInfos, property.GetGetMethod());
AddMethodInfoIfValid(interfaceMethodInfos, property.GetSetMethod());
}
foreach (var method in interfaceType.GetMethods())
{
AddMethodInfoIfValid(interfaceMethodInfos, method);
}
foreach (var methodinfo in interfaceMethodInfos)
{
int paramcount = methodinfo.GetParameters().Length;
object[] args = new object[paramcount];
Action<Interface> lambdacall = (i) => methodinfo.Invoke(i, args);
var calls = rhinomock.GetArgumentsForCallsMadeOn(lambdacall);
foreach (var call in calls)
{
bool more = false;
callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
foreach (var parameter in call)
{
if (more) { callbuilder.Append(", "); }
if (null == parameter) { callbuilder.Append("<null>"); }
else {
callbuilder
.Append('(').Append(parameter.GetType().Name).Append(")'")
.Append(parameter.ToString()).Append("'");
}
more = true;
}
callbuilder.Append(')');
string callInfo = callbuilder.ToString();
returnInfos.Add(callInfo);
}
}
return returnInfos;
}
private static void AddMethodInfoIfValid(List<MethodInfo> interfaceMethodInfos, MethodInfo methodinfo)
{
if (null != methodinfo)
{
interfaceMethodInfos.Add(methodinfo);
}
}
}
}
I have the email address of a Lync user and want to send him an instant message.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Lync.Model;
using Microsoft.Lync.Model.Conversation;
namespace Build_Server_Lync_Notifier
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Usage: bsln.exe <uri> <message>");
return;
}
LyncClient client = Microsoft.Lync.Model.LyncClient.GetClient();
Contact contact = client.ContactManager.GetContactByUri(args[0]);
Conversation conversation = client.ConversationManager.AddConversation();
conversation.AddParticipant(contact);
Dictionary<InstantMessageContentType, String> messages = new Dictionary<InstantMessageContentType, String>();
messages.Add(InstantMessageContentType.PlainText, args[1]);
InstantMessageModality m = (InstantMessageModality) conversation.Modalities[ModalityTypes.InstantMessage];
m.BeginSendMessage(messages, null, messages);
//Console.Read();
}
}
}
Screenshot
Link to large screenshot: http://i.imgur.com/LMHEF.png
As you can see in this screenshot, my program doesn't really seem to work, even though I'm able to manually search up the contact and send an instant message manually.
I also tried using ContactManager.BeginSearch() instead of ContactManager.GetContactByUri(), but got the same result (you can see in the screenshot): http://pastie.org/private/o9joyzvux4mkhzsjw1pioa
Ok, so I got it working now. Got it in a working state, although I need to do some serious refactoring.
Program.cs
using System;
namespace Build_Server_Lync_Notifier
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Usage: bsln.exe <uri> <message>");
return;
}
LyncManager lm = new LyncManager(args[0], args[1]);
while (!lm.Done)
{
System.Threading.Thread.Sleep(500);
}
}
}
}
LyncManager.cs
using Microsoft.Lync.Model;
using Microsoft.Lync.Model.Conversation;
using System;
using System.Collections.Generic;
namespace Build_Server_Lync_Notifier
{
class LyncManager
{
private string _uri;
private string _message;
private LyncClient _client;
private Conversation _conversation;
private bool _done = false;
public bool Done
{
get { return _done; }
}
public LyncManager(string arg0, string arg1)
{
_uri = arg0;
_message = arg1;
_client = Microsoft.Lync.Model.LyncClient.GetClient();
_client.ContactManager.BeginSearch(
_uri,
SearchProviders.GlobalAddressList,
SearchFields.EmailAddresses,
SearchOptions.ContactsOnly,
2,
BeginSearchCallback,
new object[] { _client.ContactManager, _uri }
);
}
private void BeginSearchCallback(IAsyncResult r)
{
object[] asyncState = (object[]) r.AsyncState;
ContactManager cm = (ContactManager) asyncState[0];
try
{
SearchResults results = cm.EndSearch(r);
if (results.AllResults.Count == 0)
{
Console.WriteLine("No results.");
}
else if (results.AllResults.Count == 1)
{
ContactSubscription srs = cm.CreateSubscription();
Contact contact = results.Contacts[0];
srs.AddContact(contact);
ContactInformationType[] contactInformationTypes = { ContactInformationType.Availability, ContactInformationType.ActivityId };
srs.Subscribe(ContactSubscriptionRefreshRate.High, contactInformationTypes);
_conversation = _client.ConversationManager.AddConversation();
_conversation.AddParticipant(contact);
Dictionary<InstantMessageContentType, String> messages = new Dictionary<InstantMessageContentType, String>();
messages.Add(InstantMessageContentType.PlainText, _message);
InstantMessageModality m = (InstantMessageModality)_conversation.Modalities[ModalityTypes.InstantMessage];
m.BeginSendMessage(messages, BeginSendMessageCallback, messages);
}
else
{
Console.WriteLine("More than one result.");
}
}
catch (SearchException se)
{
Console.WriteLine("Search failed: " + se.Reason.ToString());
}
_client.ContactManager.EndSearch(r);
}
private void BeginSendMessageCallback(IAsyncResult r)
{
_conversation.End();
_done = true;
}
}
}
Try Below Code its working Fine For me
protected void Page_Load(object sender, EventArgs e)
{
SendLyncMessage();
}
private static void SendLyncMessage()
{
string[] targetContactUris = {"sip:xxxx#domain.com"};
LyncClient client = LyncClient.GetClient();
Conversation conv = client.ConversationManager.AddConversation();
foreach (string target in targetContactUris)
{
conv.AddParticipant(client.ContactManager.GetContactByUri(target));
}
InstantMessageModality m = conv.Modalities[ModalityTypes.InstantMessage] as InstantMessageModality;
m.BeginSendMessage("Test Message", null, null);
}