I'm trying to make my client subscribe to events that happen on my server.
I have an interface that looks like this:
public delegate void RemoteEventHandler(object sender, ClientEventArgs args);
[Serializable]
public class ClientEventArgs : EventArgs
{
public ClientEventArgs()
{ }
public ClientEventArgs(Client _client)
{
MyClient = _client;
}
public Client MyClient { get; set; }
}
public interface IMonitor
{
event RemoteEventHandler RemoteEvent;
}
My Server Class looks like this:
public class ConnectionManager : MarshalByRefObject, IMonitor
{
public event RemoteEventHandler RemoteEvent;
// call the below code when th event should fire.
if (RemoteEvent != null)
RemoteEvent(this, new ClientEventArgs(e.MyClient));
}
Then To set my channels up on the server I do this:
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = 5001;
TcpChannel channel = new TcpChannel(props, null, provider);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(ConnectionManager),
ConnectionManager",
WellKnownObjectMode.Singleton);
And On the client to set the channels up and subscribe to the event:
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel, false);
_monitorObject = (IMonitor)Activator.GetObject(
typeof(IMonitor),
"tcp://localhost:5001/ConnectionManager");
_monitorObject.RemoteEvent += _monitorObject_RemoteEvent;
Can anyone explain where this is going wrong please?
Exception:
System.MissingMethodException was unhandled HResult=-2146233069 Message=No parameterless constructor defined for this object.
Source=mscorlib
To answer your last question: when using Serializable you need a constructor without parameters. So this one would definitely fail:
[Serializable]
public class ClientEventArgs : EventArgs
{
public ClientEventArgs(Client _client)
{
MyClient = _client;
}
public Client MyClient { get; set; }
}
You need to add a parameterless constructor:
[Serializable]
public class ClientEventArgs : EventArgs
{
public ClientEventArgs()
{ }
public ClientEventArgs(Client _client)
{
MyClient = _client;
}
public Client MyClient { get; set; }
}
My money is on your ConnectionManager class not having a default / parameterless constructor. The remoting infrastructure needs to be able to create an instance of it on the server end.
Related
I have a custom module MyModule with a custom plugin MyPlugin in this plugin I want to send and receive data via a BinaryConnection.
Here is a simplified version of my code
[ServerModule(ModuleName)]
public class ModuleController : ServerModuleBase<ModuleConfig>
{
protected override void OnInitialize()
{
Container.LoadComponents<IMyPlugin>();
}
protected override void OnStart()
{
Container.Resolve<IBinaryConnectionFactory>();
Container.Resolve<IMyPlugin>().Start();
}
}
[Plugin(LifeCycle.Singleton, typeof(IMyPlugin), Name = PluginName)]
public class MyPlugin: IMyPlugin
{
private IBinaryConnection _connection;
public IBinaryConnectionFactory ConnectionFactory { get; set; }
public IBinaryConnectionConfig Config { get; set; }
public void Start()
{
_connection = ConnectionFactory.Create(Config, new MyMessageValidator());
_connection.Received += OnReceivedDoSomething;
_connection.Start();
}
}
When I start the Runtime I get a NullReferenceException because the ConnectionFactory is not injected. Where is my mistake here?
To use the binary connection in your module you can either instantiate TcpClientConnection and TcpListenerConnection manually or use your modules DI-Container, as you already tried and I would recommend.
To use it in your module, you need to register/load the classes into your container. Take a look at how the Resource Management registers them. In your OnInitialize you need:
Container.Register<IBinaryConnectionFactory>(); // Register as factory
Container.LoadComponents<IBinaryConnection>(); // Register implementations
Then you can add either a BinaryConnectionConfig entry to your config and decorate with [PluginConfigs(typeof(IBinaryConnection), false)] to select Socket as well as Client/Server from the MaintenanceWeb or use the derived type TcpClientConfig/TcpListenerConfig directly.
public class ModuleConfig : ConfigBase
{
[DataMember, PluginConfigs(typeof(IBinaryConnection), false)]
public BinaryConnectionConfig ConnectionConfig { get; set; }
}
In you plugin you can then inject IBinaryConnectionFactory and ModuleConfig to create the connection.
public class MyPlugin: IMyPlugin
{
private IBinaryConnection _connection;
public IBinaryConnectionFactory ConnectionFactory { get; set; }
public ModuleConfig Config { get; set; }
public void Start()
{
_connection = ConnectionFactory.Create(Config.ConnectionConfig, new MyMessageValidator());
_connection.Received += OnReceivedDoSomething;
_connection.Start();
}
}
PS: Resolving the factory in OnStart returns an instance, which you don't use and is unnecessary. Don't confuse Resolve(Find registered implementation and create instance) with Register.
Hello i have a very big problem. I need to take/create connection to one core with single type and make any operations.
For now its looks like:
public class SolrMachine<T> : ISolrMachine<T> where T : ISolrRecord
{
private ISolrOperations<T> actuallyInstance { get; set; }
public SolrMachine(string coreName)
{
string url = String.Format("http://xxxx/solr/{0}", coreName);
ISolrConnection solrConnection = new SolrConnection(url) { HttpWebRequestFactory = new SolrAuthWebRequestFactory()};
Startup.Init<T>(solrConnection);
var myInstance = ServiceLocator.Current.GetInstance<ISolrOperations<T>>();
this.actuallyInstance = myInstance;
}
}
ISolrMachine<T> is a interface with my methods to operate on solr core. ISolrRecord is a interface with properties in my cores.
Now, when I am doing a connection with two other cores all works perfectly.
SolrMachine<SolrTypeOne> firstCoreConnection = new SolrMachine<SolrTypeOne>(firstCoreName);
SolrMachine<SolrTypeTwo> secondCoreConnection = new SolrMachine<SolrTypeTwo>(secondCoreName);
// operation on firstCoreConnection and secondCoreConnection works
But when I'm trying to connect with one type and one coreName i have exception on Startup.Init<T>(solrConnection). I know that Startup container blocks a connection with same Type and coreName but always I am creating a new instance to this SolrMachine. I expect this:
class SomeClass
{
public MyMethod()
{
SolrMachine<SolrTypeOne> myConn = new SolrMachine<SolrTypeOne>(firstCoreName);
// operation
}
}
class SecondSomeClass
{
public MyMethod()
{
SolrMachine<SolrTypeOne> myConn2 = new SolrMachine<SolrTypeOne>(firstCoreName);
// here it's not work
}
}
How to avoid this ?
In my case, problem was that my Solr using a IHttpWebRequestFactory. From SolrNet multicore documentation author doesn't take this problem. Here is my solution (use Windsor):
public class SolrAuth : IHttpWebRequestFactory
{
public IHttpWebRequest Create(Uri url)
{
//... credentials, timeouts, etc.
return new HttpWebRequestAdapter((HttpWebRequest)webrequest);
}
}
public class SolrMachine<T> : ISolrMachine<T> where T : ISolrRecord
{
public WindsorContainer myContainer = new WindsorContainer();
private ISolrOperations<T> actuallyInstance { get; set; }
public SolrMachine(string coreName)
{
var url = string.Format("http://xxx/solr/{0}", coreName);
myContainer.Register(Component.For<IHttpWebRequestFactory>().ImplementedBy<SolrAuth>());
var solrFacility = new SolrNetFacility(string.Format("http://xxx/solr/{0}", "defaultCollection"));
solrFacility.AddCore(coreName, typeof(T), url);
myContainer.AddFacility(solrFacility);
this.actuallyInstance = myContainer.Resolve<ISolrOperations<T>>();
}
}
I have a email service which passes an email model through the constructor and that all using the same base class. For example one model could be for authentication, another model for password reset. My problem is how to allow the service to pass an anonymous model with the same base class.
sample code:
public class EmailService<T> : IEmailService
{
private readonly T _emailModel;
private readonly EmailType _emailType;
private readonly IEmailRepository _emailRepository;
private MailBuilder _mailBuilder;
private EmailTemplates _message;
public EmailService(T emailModel, EmailType emailType, IEmailRepository emailRepository)
{
_emailModel = emailModel;
_emailType = emailType;
_emailRepository = emailRepository;
getMessage();
constructEmail();
}
private void getMessage()
{
_message = _emailRepository.GetTemplateByUser((int)_emailType, _emailModel.UserTypeId);
}
private void constructEmail()
{
_mailBuilder = new MailBuilder(_message, _emailType, ObjectConverters.ConvertProperiesToDictionary(_emailModel));
}
public void Send()
{
EmailSettings emailSettings = SiteSettingsService.SiteConfiguration.EmailSettings;
MailSettings settings = new MailSettings
{
MailFrom = emailSettings.MailFrom,
MailSmtpHost = emailSettings.SmtpHost,
MailSmtpPort = emailSettings.SmtpPort,
EnableSsi = emailSettings.EnableSsi,
MailSmtpUsername = emailSettings.SmtpUsername,
MailSmtpPassword = emailSettings.SmtpPassword
};
new EmailSender(settings).SendEmail(_emailModel.EmailAddress, _message.Title, _mailBuilder.HtmlTemplate);
}
}
You could have the derived classes all implement a new IModel interface, which your EmailService class then accepts via ctor.
public class AuthenticationModel : BaseModel, IModel
{
public void PerformMainFunction()
{
// authenticate
}
}
public class PasswordResetModel : BaseModel, IModel
{
public void PerformMainFunction()
{
// reset password
}
}
public class BaseModel
{
public int UserTypeId { get; set; }
}
public interface IModel
{
void PerformMainFunction();
int UserTypeId { get; set; }
}
public class EmailService : IEmailService
{
private readonly IModel _emailModel;
...
public EmailService(IModel emailModel, EmailType emailType, IEmailRepository emailRepository)
{
_emailModel = emailModel;
...
You could use something like unity to inject the dependency or, for now, just do:
IModel model = new AuthenticationModel();
var eServ = new EmailService(model, ....
I thought of a better way. We always convert our object to a dictionary in the service. Maybe we convert it from the service calling the email service so we're always passing a dictionary instead of an interface, that way we don't need to know about the structure. The dictionary will always be a key value of string and string.
Let's assume, that we have the following classes:
class ViewModelA
{
private ProxyA proxy;
public ViewModelA(DataA data)
{
proxy = new ProxyA(data);
}
public void DoSth()
{
proxy.DoSth();
}
public ProxyA Proxy
{
get
{
return proxy;
}
}
}
class ViewModelB
{
private ProxyB proxy;
public ViewModelB(DataB data)
{
proxy = new ProxyB(data);
}
public void DoSth()
{
proxy.DoSth();
}
public ProxyB Proxy
{
get
{
return proxy;
}
}
}
...
All of these classes are actually a lot longer, but also similar in the same degree.
Is there a (nice) way of converting them all to one generic class? The core problem is the line:
proxy = new ProxyA(data);
because C# disallows calling parametrized ctors on generic class specializations (in terms of T).
You can solve this by passing in a preconstructed ProxyA or ProxyB object.
One way of doing it is through inheritance, constructing the object just before calling the base constructor:
class ViewModel<TProxy, TData>
{
private TProxy proxy;
public ViewModel(TProxy proxy)
{
this.proxy = proxy;
}
public void DoSth()
{
proxy.DoSth();
}
public TProxy Proxy
{
get
{
return proxy;
}
}
}
class ViewModelA : ViewModel<ProxyA, DataA>
{
public ViewModelA(DataA data) : base(new ProxyA(data))
{
}
}
I've assumed here that DataA and DataB occurs somewhere in method signatures that you have omitted. If not, you can leave out the TData generic type parameter.
Reflection is always an option, but it is best avoided if a solution like this is acceptable. If you want to avoid having to create a new type for a different TProxy and TData, you could add a second constructor instead:
ViewModel(TData data, Func<TData, TProxy> factory) : this(factory(data))
{
}
Used as such:
new ViewModel<ProxyA, DataA>(new DataA(), data => new ProxyA(data));
I'm not sure if that makes sense to do in your application however.
If you know the type (and using generics you would), you can call Activator.CreateInstance to create an instance of that type using any constructor you want.
proxy = Activator.CreateInstance(typeof(TProxy), new[]{data});
While this will solve your direct problem, you could also think about a design where ViewModelA does not know about DataA and instead gets passed a ProxyA. That would solve all your problems without fancy reflection.
As you noted, it is not possible to do this with parameterised constructors, without using reflection. However, one possible variation on this theme:
public interface IDataProxy<T>
{
T Data { get; set; }
}
public class ViewModel<TProxy, TData>
where TProxy : class, new, IDataProxy<TData>
{
public TProxy Proxy { get; private set; }
public ViewModel(TData data)
{
Proxy = new TProxy { Data = data };
}
}
public interface IProxy
{
void DoSth();
}
public class ProxyA : IProxy
{
public ProxyA(DataA dataA)
{
}
public void DoSth()
{ }
}
public class ProxyB : IProxy
{
public ProxyB(DataB dataA)
{
}
public void DoSth()
{
}
}
public class ViewModel<T> where T : IProxy
{
private readonly IProxy _proxy;
public ViewModel(T proxy)
{
_proxy = proxy;
}
public void DoSth()
{
_proxy.DoSth();
}
}
var vm = new ViewModel<ProxyA>(new ProxyA(new DataA()));
vm.DoSth();
public interface IDoSomething
{
void DoSth();
}
class ViewModel<T> where T : IDoSomething
{
private T proxy;
public ViewModel()
{
proxy = Activator.CreateInstance<T>();
}
//public ViewModel(T data)
//{
// proxy = data;
//}
public void DoSth()
{
proxy.DoSth();
}
public T Proxy
{
get
{
return proxy;
}
}
}
I'm trying to hook the event (Action in that case) but cant return from proxy without exception. Here's the idea: I have the interface of events, they not subscribed on client side. So when I try raise event on client side, I catch this event in proxy and send to my remote server the name of this event and his parameters and i wanna just return from proxy. Here my sample
public interface IMyEvents
{
Action OnPing { get; set; }
}
public class Proxy : RealProxy
{
Type type;
public Proxy(Type type)
: base(type)
{
this.type = type;
}
public override IMessage Invoke(IMessage msg)
{
var call = (IMethodCallMessage)msg;
string MethodName = (string)msg.Properties["__MethodName"];
object[] parameters = (object[])msg.Properties["__Args"];
// Send Command to server
// SendData(MethodName, parameters);
// tell the invoker that everything's fine
return new ReturnMessage(null, null, 0, call.LogicalCallContext, call);
}
}
public class Test
{
public Test()
{
Proxy proxy = new Proxy(typeof(IMyEvents));
Events = (IMyEvents)proxy.GetTransparentProxy();
}
public readonly IMyEvents Events;
}
class Program
{
public static void Main(string[] args)
{
Test t = new Test();
t.Events.OnPing(); // NullReferenceException
}
}