CodeProject; Tools & Code: A Write-Once/Use-Everywhere Web Service
A Pick From The “Code Project”

A LEAN AND MEAN WEB SERVICE
Click title for source & download at the CodeProject.com…
By Xiangyang Liu.
Write one web service, use it everywhere
What is it?
LMService is not just another web service. It is a write-once / use-everywhere web service. About the “lean” part, it has only 25 lines of code, not counting the code automatically generated by Visual Studio .NET. You will see how “mean” it is when you read the rest of the article.
The code included was developed using Visual Studio .NET 2003 and tested on Windows 2000, Windows XP, and Windows 2003.
What does it do?
Once you deployed the web service to a server, you can use it to invoke code in almost any .NET dll on the server. For anything you want to do on the server, just write a .NET dll following certain rules (to be explained later) and copy the dll onto the server. Then you can execute your dll code from any client machine by calling LMService.
How does it work?
LMService has only one web method InvokeMethod with the following signature:
public object InvokeMethod(string sDllPath, string sClassName, string sMethodName, object[] pInput)
{
// implementation of the web method
}
Parameter sDllPath is the full path of a .NET dll which contains the code you want to invoke; Parameter sClassName is the name of a public class in the dll; Parameter sMethodName is the name of a public method in the class, i.e. name of the method to be invoked; Finally, pInput is an object array containing input values to be used when invoking the method. As long as you pass the right parameters, InvokeMethod will do the rest for you, including
* Load the dll with given path into the server process.
* Create an instance of the corresponding class.
* Call the method with given name passing all values in object array pInput as parameters
* Finally, return an output object to the caller.
As a lean and mean web service, LMService loads each dll only once caching certain information in memory to improve performance.
Execute code on a remote server as if it were local
For your convenience, I have included LMClient.dll (another three lines of code). This dll makes it easier to call LMService. There is a static method InvokeMethod in the dll. The signature of this static method is almost the same as the web method in LMService, the only difference is that you need to provide an extra parameter (the first one): the URL of the web service.
Suppose Hello.dll is a .NET dll and you have copied Hello.dll onto a server where LMService is deployed. Suppose Hello.dll contains a class HelloClass with a public method Hello, and the Hello method takes your name as input string and returns string “Hello, YourName”. Here is a complete test program to invoke the Hello method on the server.
static void Main(string[] args)
{
string sOutput = (string)LMClient.Client.InvokeMethod
(
“http://MyServer/LMService/LMService.asmx”, // url of web service
“C:\\Hello\\Hello.dll”, // dll path
“HelloClass”, // class name
“Hello”, // method name
new object[1]{“Xiangyang Liu”} // array that contains user name string
);
System.Console.Out.WriteLine(sOutput);
}
// output of the above program is: “Hello, Xiangyang Liu”
Rules? What rules?
Ok, I may have misled you. You cannot use LMService to execute code in any .NET dll. Your code has to be written following certain rules:
* The method to be invoked by LMService has be a public method in a public class within a .NET dll. The public class needs a default constructor.
* Type of each input parameter of the method can be:
1. basic types (int, long, double, byte, string, datetime, etc.)
2. byte array
3. object
4. object array while each element in the array can be basic types, byte array, object, or object array (while each element of the array can be …).
* The output of the method subjects to the same type restriction as the input.
Note that the number of input parameters is not limited by the above rules. Here are some methods in compliance with the above rules:
public byte[] GetFile(string sFilePath)
{
// return content of specified file in a byte array
}
public void PutFile(string sFilePath, byte[] pData)
{
// save data in the byte array to file with given path
}
public object[] Search(DateTime oStart, DateTime oEnd, string sFilter1, string sFilter2)
{
// 1. find all records with timestamp between oStart and oEnd
// and satisfying the two search conditions
// 2. return data is an object array, each item in the array
// is an object array representing a found record
}
The above rules seem to be harsh, however, since object array (and array of object arrays) is allowed as input and output types, you can use almost any “data structure” as input/output. For example, if your method needs to return a set of records from a database table, you can use an object array as the return value while each element of the array is itself an object array representing a record in the table. The following code builds an object array that could be used as input/output value of your method (to be invoked by LMService).
// array of 100 records
object[] pData = new object[100];
// first record
pData[0] = new object[3];
// name
((object[])pData[0])[0] = “James”;
// age
((object[])pData[0])[1] = 13;
// data of birth
((object[])pData[0])[2] = Convert.ToDateTime(“1/1/1993″);
// second record
pData[1] = new object[3];
// name
((object[])pData[1])[0] = “Thomas”;
// age
((object[])pData[1])[1] = 10;
// data of birth
((object[])pData[1])[2] = Convert.ToDateTime(“2/2/1997″);
…
The restriction on input/output types is necessary because LMService does not have any knowledge of the code it is going to invoke. Even if you restrict the types to string, you can still use XML format to represent any kind of data. As a famous CPian once said, “At the end of day, it is just text anyway.”
Summary
Now, what do we have so far?
* A web service, LMService, that can run on any server. Once deployed, you can use it to invoke .NET code on that server, as long as the code is in a .NET dll and follows some simple rules.
* A library LMClient.dll. Using this dll you can invoke code on remote server as if you are making a local library call.
Exercise
It is easy to enhance LMService and use it to develop complicated business applications. For example, I included another simple .NET component FileLib.dll. Using this dll and LMService, you can write a console program with only a few lines of code to upload file to the server and/or download file from the server, assuming you know the exact path of the file. This is left as an exercise for you. If you have to write more than a few lines of code to do this, then you are not using LMService correctly.
Hint: 1. Copy FileLib.dll to the server first. 2. You can also use FileLib.dll on the client-side to save downloaded file.
I know what you are thinking
What about security and all the other important issues in building complicated business applications? Well, what do you expect from a web service that has only 25 lines of code? I have written my own business application framework that has a lot of useful features and addresses some of the important issues. It is free (but source code is not provided, sorry).
Warning
Deploying LMService could lead to security problems, because it allows all clients to execute almost any .NET code on your server, including code you never knew existed. In other words, you better know what you are doing. For example, if you need help to open a web project from Visual Studio .NET or you are not familiar with creating/configuring a virtual directory in IIS, then this web service is not for you.
You may have noticed that I am writing C style code in C#. I know it can be annoying to some people, but honestly, I enjoyed it.
Thank you for reading my articles.
About this entry
You’re currently reading “CodeProject; Tools & Code: A Write-Once/Use-Everywhere Web Service,” an entry on TECH NOTES
- Published:
- March 20, 2007 / 2:51 pm
- Category:
- Code Project Picks
- Tags:
2 Comments
Jump to comment form | comment rss [?] | trackback uri [?]