C# Remoting classes organization - c#

I'm developing a Remoting classes library so that I can keep database interaction and business object on the server and not on clients.
I'd like to be able to return my own objects to the clients so that they can interact with them through the server itself.
For example (semi-pseudocode):
Server
class Database { ... }
class Utility
{
public User getUser(username)
{
return new User(username);
}
}
class User
{
public string[] getPerms()
{
return Database.query("select * from permission where user = " + this.username);
}
}
Client
Utility utility = (Utility)getRemotingClass("Utility");
User user = Utility.getUser("admin");
string[] perms = user.getPerms();
How can I organize my classes/namespaces? I'm particularly wondering about class references and scalability of my system.
Any kind of criticism/suggestion is really appreciated.

I don't mean to beat a drum, but you might want to look into WCF. Remoting is very chatty and the real support for maintaining clean interfaces by .Net is being done through WCF and message passing, as opposed to full object state management through remoting.
What it sounds like you are doing is developing a middle tier for management of the database connections. Just make sure you don't end up redeveloping the interface to SQL server.

I tend to put all the 'shared' (Data Transfer Object) classes in a separate DLL which both the server and the client reference (you could put them in the same DLL as the server classes if you're going to distribute it with the client code anyway).
By putting them in a separate assembly, you reinforce the de-coupling of the DTOs and the underlying technology used to remotely transfer them.
This means that if you end up rewriting the remote call technology, you won't have to touch the DTOs and can just re-use the assembly.
Don't forget to mark the DTOs as with the [Serailizable] attribute so they can be transported between the client and the server.
Herbie

Related

WCF - how to connect to specific instance

Using WCF, .NET 4.5, Visual Studio 2015, and want to use per-session instancing, not singleton. The services provided are to be full-duplex, over tcp.net.
Suppose I have two machines, A & B...
B as a client, connects to a "service" provided as a WCF service on same machine B, and starts talking to it, call it object “X”. It ALSO connects to another instance of the same service, call it object “Y”
A as a client, wants to connect to, and use, exact same objects B is talking to, objects “X” and “Y”, except now it’s remote-remote, not local-remote.
“X” and “Y” are actually a video servers, and both have “state”.
Can I do this? How, when I’m a client, do I specify WHICH service instance I want to connect to?
Obviously, on machine "B", I could kludge this by having the services just be front-ends with no "state", which communicate with some processes running on "B", but that would require I write a bunch of interprocess code, which I hate.
Machine B is expected to be running 100's of these "video server" instances, each one being talked to by a local master (singleton) service, AND being talked to by end-user machines.
I realize this question is a bit generic, but it also addresses a question I could not find asked, or answered, on the Internets.
I just thought of one possible, but kludge-y solution: since the master service is a singleton, when service instance "X" is created by the end-user, it could connect to the singleton master service, through a proxy to the singleton. Then, the singleton can talk back to instance "X" over a callback channel. Yeah, that would work! messy, but possible.
I'd still like to know if end user A and end user B can both talk to the same (non-singleton) service instance on machine C through some funky channel manipulation or something. As I understand the rules of WCF, this simply isn't possible. Perhaps maybe if you're hosting the service yourself, instead of IIS, but even then, I don't think it's possible?
I've faced the same problem and solved it by creating two service references, one for the local one for the remote. Let's call it LocalServiceClient and RemoteServiceClient.
In a class, create a property called Client (or whatever you like to call it):
public LocalServiceClient Client {
get {
return new LocalServiceClient();
}
}
Okay this is for only one of them. Just create another now, and set which one to use with a compiler flag:
#if DEBUG
public LocalServiceClient Client {
get {
return new LocalServiceClient();
}
}
#else
public RemoteServiceClient Client {
get {
return new RemoteServiceClient();
}
}
#endif
Instantiate any instances of your Client using var keyword, so it will be implicitly-typed, or just use Client directly:
var client = Client;
client.DoSomething...
//or
Client.DoSomething...
This way, when you are working locally, it will connect to the local service, and on release configuration (make sure you are on Release when publishing) it will compile for the remote one. Make sure you have the exact same signature/code for both services though at the WCF-side.
There are also methods that you can dynamically do it in code, or like in web.config, they would also work for sure, but they are usually an overkill. You probably need to connect to local one in debugging, and the remote one in production, and this is going to give you exactly what you need.

Communicating between C# and Visual C++ over IPC port (OR: Sharing a type between a Visual C++ DLL and a C# application)

I have a DLL written in Visual C++ and an application written in C#. The application that is written in C# already uses IPC between multiple instances of itself so that it only ever runs one instance (it attempts to start an IPC server, and if it can't assumes there's already one running, in which case it sends the command line arguments over IPC to the existing application).
Now I want to send commands from a Visual C++, however, even when I create a type definition in Visual C++ that matches the one in C# (on an implementation level), it rejects the connection because they are fundamentally still two different types (from two different assemblies).
I thought about using Reflection in Visual C++ to fetch the type from the C# assembly, but I can't do that because then I'd have to ship the assembly along side the DLL (which defeats the purpose of the DLL being an API to the application).
I'm not sure of any other way I could really do it, other than store the class in yet another DLL and make both the application and the API DLL reference the class in that, but this is also not an ideal solution as I'd like a single API DLL to distribute.
Are there any suggestions as to how I can connect over IPC (other forms of communication like TCP are not permitted) to send requests to the application?
The solution was to place the InterProcess class in the API DLL and simply make the C# application use the DLL as a reference to bring in the class.
It is also important to note that in order to initialize the shared object correctly, I had to initialize the server side of the sharing in a separate AppDomain and make the C# application a client like so (this is a new version of the previous paste):
try
{
// Set up an interprocess object which will handle instructions
// from the client and pass them onto the main Manager object.
this.m_ServerDomain = AppDomain.CreateDomain("roketpack_server");
this.m_ServerDomain.DoCallBack(() =>
{
// We must give clients the permission to serialize delegates.
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
IpcServerChannel ipc = new IpcServerChannel("roketpack", "roketpack", serverProv);
ChannelServices.RegisterChannel(ipc, true);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(API.InterProcess),
"InterProcessManager",
WellKnownObjectMode.Singleton);
});
// Now initialize the object.
IpcClientChannel client = new IpcClientChannel();
ChannelServices.RegisterChannel(client, true);
this.m_InterProcess = (API.InterProcess)Activator.GetObject(
typeof(API.InterProcess),
"ipc://" + name + "/InterProcessManager");
InterProcessHandle.Manager = this;
this.m_InterProcess.SetCalls(InterProcessHandle.CallURL,
InterProcessHandle.IsLatestVersion,
InterProcessHandle.RequestUpdate);
return true;
}
catch (RemotingException)
{
// The server appears to be already running. Connect to
// the channel as a client and send instructions back
// to the server.
IpcClientChannel client = new IpcClientChannel();
ChannelServices.RegisterChannel(client, true);
API.InterProcess i = (API.InterProcess)Activator.GetObject(
typeof(API.InterProcess),
"ipc://" + name + "/InterProcessManager");
if (i == null)
{
Errors.Raise(Errors.ErrorType.ERROR_CAN_NOT_START_OR_CONNECT_TO_IPC);
return false;
}
if (Environment.GetCommandLineArgs().Length > 1)
i.CallURL(Environment.GetCommandLineArgs()[1]);
return false;
}
I hope this solution helps someone else :)

Custom API requirement

We are currently working on an API for an existing system.
It basically wraps some web-requests as an easy-to-use library that 3rd party companies should be able to use with our product.
As part of the API, there is an event mechanism where the server can call back to the client via a constantly-running socket connection.
To minimize load on the server, we want to only have one connection per computer. Currently there is a socket open per process, and that could eventually cause load problems if you had multiple applications using the API.
So my question is: if we want to deploy our API as a single standalone assembly, what is the best way to fix our problem?
A couple options we thought of:
Write an out of process COM object (don't know if that works in .Net)
Include a second exe file that would be required for events, it would have to single-instance itself, and open a named pipe or something to communicate through multiple processes
Extract this exe file from an embedded resource and execute it
None of those really seem ideal.
Any better ideas?
Do you mean something like Net.TCP port sharing?
You could fix the client-side port while opening your socket, say 45534. Since one port can be opened by only one process, only one process at a time would be able to open socket connection to the server.
Well, there are many ways to solve this as expressed in all the answers and comments, but may be the simpler way you can use is just have global status store in a place accesible for all the users of the current machine (may be you might have various users logged-in on the machine) where you store WHO has the right to have this open. Something like a "lock" as is used to be called. That store can be a field in a local or intranet database, a simple file, or whatever. That way you don't need to build or distribute extra binaries.
When a client connects to your server you create a new thread to handle him (not a process). You can store his IP address in a static dictionary (shared between all threads).
Something like:
static Dictionary<string, TcpClient> clients = new Dictionary<string, TcpClient>();
//This method is executed in a thread
void ProcessRequest(TcpClient client)
{
string ip = null;
//TODO: get client IP address
lock (clients)
{
...
if (clients.ContainsKey(ip))
{
//TODO: Deny connection
return;
}
else
{
clients.Add(ip, client);
}
}
//TODO: Answer the client
}
//TODO: Delete client from list on disconnection
The best solution we've come up with is to create a windows service that opens up a named pipe to manage multiple client processes through one socket connection to the server.
Then our API will be able to detect if the service is running/installed and fall back to creating it's own connection for the client otherwise.
3rd parties can decide if they want to bundle the service with their product or not, but core applications from our system will have it installed.
I will mark this as the answer in a few days if no one has a better option. I was hoping there was a way to execute our assembly as a new process, but all roads to do this do not seem very reliable.

.net windows service as a state server

i'd like to create a windows service that would be accessible via WCF from a web application.
The workflow would be:
Windows Service starts and would hold a default value in memory.
A web app would connect the windows service via wcf and take the value and after some processing set the value back in the memory.
In a while would happend the same as in point 2., and so on,so on
This value would be hold only in memory.
The point is I dont know where put the variable that would be hold in the memory of the windows service.There is a Service class wich is instancied in a Program class wich is static class. So whats the best place to put a variable that would be hold in the memory as long as the service is running ?
And second question,is it correct to reference the exe of the windows service in a DLL ??
There is a service class for every windows service that also contains the start and stop methods. However, for your service, I'd simply create a singleton class that is accessed from the class that handles the WCF client requests.
There's no need to reference the exe of the service (and I strongly recommend you not to do that), as when you're using WCF you'll insert a service reference into your client project and just need two methods to get and set the data.
I suggest: Design your operation and data contracts for the service and then create the service reference within your client project. That'll make things clear.
If you don't know what I'm talking about, I recommend googleing for WCF samples.
EDIT
You write in the comment that you created a service class with a private field. I suppose you didn't actually do what I suggested :-) I said: Create a singleton class that is accessed by the class that handles the get/set requests.
public class ValueHolder
{
private static ValueHolder m_singleton = null;
private int m_someValue;
private ValueHolder()
{
m_someValue = 0;
}
public static ValueHolder Instance
{
get
{
if (m_singleton = null)
m_singleton = new ValueHolder();
return m_singleton;
}
}
public int SomeValue
{
get { return m_someValue; }
set { m_someValue = value; }
}
}
So now you have a window service class that you use to host a WCF service. The WCF service contains methods to get/set the value from ValueHolder.Instance.SomeValue. These methods are exposed to the client using the data contract.
Start your service and add a service reference to the client using the respective option in Visual Studio (not a reference to the DLL, but a service reference!!). The client now accesses the get/set methods of the service.
Job done, where's my money? :-D
It almost sounds like a separate service might be a little overkill for what you're after - maybe you should take a look at Inter-Process shared memory.
Take a look at #3 in this article.
http://www.codeproject.com/KB/threads/csthreadmsg.aspx

Connecting to a database from the beginning

I have been working in a business writing advanced software apps, and obviously im provided with access to our SQL server and all the connection strings needed.This is fine for my job now - but what if i wanted to do this for a new (very small) business... If i wanted to purchase a small database server and set up a piece of software that talks to the databases on this server, how would i go about a) Talking and connecting to the server in code (c#) and b)What would i need regarding things like internet/phone connections etc to make this possible.
Edit: the reason it would need a server is because it would need to be accessed from 2 or 3 different computers in different locations?
Actually there are quite a few ways to create a database connection, but I would say one of the easiest ways is to utilize the methods and classes found in System.Data.SQLClient. A basic connection would look something like the following:
using System.Data.SQLClient;
namespace YourNamespace
{
public class DatabaseConnect
{
public DataType getData()
{
DataType dataObj = new DataType();
SqlConnection testConn = new SqlConnection("connection string here");
SqlCommand testCommand = new SqlCommand("select * from dataTable", testConn);
testConn.Open()
using (SqlDataReader reader = testCommand.ExecuteReader())
{
while (reader.Read())
{
//Get data from reader and set into DataType object
}
}
return dataObj;
}
}
}
Keep in mind, this is a very, very simple version of a connection for reading data, but it should give you an idea of what you need to do. Make sure to use a "using" or "try/catch" statement to ensure that the connection is closed and resources are freed after each use (whether it successfully gets data or not).
As for your other question about what equipment you may require. In the beginning I would suggest just creating the database on your local machine and running tests from there. Once you are confident with trading data back and forth, feel free to move the database to another box or an online server. Any internet connection type should suffice, though I can't vouch for dial-up, haven't used it in years.
One final note, if you do happen to decide to move to an online server system, make sure that the service you use allows for outside connections. Certain services use shared server systems, and force users to use their internal database interfaces to manage and write to the database.
--- EDIT ---
As for the server system itself, build up a separate box on your local network that you can see, and load up the database software of your choice. Since you are using C#, it would probably be easiest to go with Microsoft SQL Server 2005 / 2008. The installation is rather straightforward, and it will prompt you to automatically create your first database while installing.
After installation it will be up to you to add in the tables, stored procedures, custom functions, etc... Once your base structure is created, go ahead and use the above code to make some simple connections. Since you are familiar with the above practices then I'm sure you know that all you really need to do is target the server machine and database in the connection string to be on your way.
In case your application is small (by small I mean the usage of resources like CPU and memory) then your SQL Server can reside on the same box.
Else you need to have a separate server box for your database and connect to that from your application. In this case, preferably your database box and application box would be on the local area network.
Check this link for having a connection to SQL Server from C# code - http://www.codeproject.com/KB/database/sql_in_csharp.aspx
cheers
You should probably expose your database with an xml web services layer, so that your architecture will be scalable. The general idea is host your sql server and webservices, using Native SQL Server XML Web Services you can make this available to your remote clients. When in your clients you simply add a service reference in Visual Studio and your data will now be available in your client app.
Hope this helps some.
Cheers
You may find the connectionstrings website useful - worth bookmarking.

Categories

Resources