|
/*
DotNetMQ - A Complete Message Broker For .NET
Copyright (C) 2011 Halil ibrahim KALKAN
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Reflection;
using System.Text;
namespace MDS.Client.MDSServices
{
/// <summary>
/// Any MDSService class must be inherited from this class.
/// </summary>
public abstract class MDSService
{
#region Public properties
/// <summary>
/// When a method of a MDSService application is invoked, this field stores address of source application in MDS.
/// </summary>
public MDSRemoteAppEndPoint RemoteApplication { get; internal set; }
/// <summary>
/// When a method of a MDSService application is invoked, this field stores the original message that is sent by MDS server.
/// </summary>
public IIncomingMessage IncomingMessage { get; internal set; }
#endregion
#region Predefined Public Service Methods
/// <summary>
/// This method generates client proxy class to use this service.
/// It is also a MDSServiceMethod, so, clients can update it's proxy classes via calling this method remotely.
/// </summary>
/// <param name="namespaceName">Namespace of generating proxy class</param>
/// <returns>Proxy class code to use this service</returns>
[MDSServiceMethod(Description = "This method generates client proxy class to use this service. Clients can update it's proxy classes via calling this method remotely.")]
[return: MDSServiceMethodParameter("Proxy class code to use this service")]
public string GenerateProxyClass([MDSServiceMethodParameter("Namespace of generating proxy class")] string namespaceName)
{
//Check parameters
if (string.IsNullOrEmpty(namespaceName))
{
namespaceName = "MDSServiceProxies";
}
//Get this Type, Methods and Attributes
var serviceType = GetType();
var methods = serviceType.GetMethods();
var attributes = serviceType.GetCustomAttributes(typeof(MDSServiceAttribute), true);
//Check for MDSService attribute
if (attributes.Length <= 0)
{
return "This class has not MDSService attribute. So, it is not a MDSService.";
}
//Get MDSService attribute
var mdsServiceAttribute = (MDSServiceAttribute)attributes[0];
//Generate class name
var proxyClassName = serviceType.Name + "Proxy";
//Start generating code
var classBuilder = new StringBuilder();
//Generate header of file.
classBuilder.AppendLine("/* This code file is generated by MDSService Proxy Generator tool.");
classBuilder.AppendLine(" * ");
classBuilder.AppendLine(" * Service Name : " + serviceType.Name);
classBuilder.AppendLine(" * Service version : " + mdsServiceAttribute.Version);
classBuilder.AppendLine(" * Generating date : " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
classBuilder.AppendLine(" */");
classBuilder.AppendLine();
//Namespaces
classBuilder.AppendLine("using System;");
classBuilder.AppendLine("using MDS.Client;");
classBuilder.AppendLine("using MDS.Client.MDSServices;");
classBuilder.AppendLine();
//Class code
classBuilder.AppendLine("namespace " + namespaceName);
classBuilder.AppendLine("{");
classBuilder.AppendLine(" /// <summary>");
classBuilder.AppendLine(" /// This class is a proxy class to use " + serviceType.Name + " service.");
if (!string.IsNullOrEmpty(mdsServiceAttribute.Description))
{
classBuilder.AppendLine(" /// Service Description: " + mdsServiceAttribute.Description);
}
classBuilder.AppendLine(" /// </summary>");
classBuilder.AppendLine(" public partial class " + proxyClassName + " : MDSServiceProxyBase");
classBuilder.AppendLine(" {");
//Constructor
classBuilder.AppendLine(" #region Constructor");
classBuilder.AppendLine(" ");
classBuilder.AppendLine(" /// <summary>");
classBuilder.AppendLine(" /// Creates a new instance of " + proxyClassName + ".");
classBuilder.AppendLine(" /// </summary>");
classBuilder.AppendLine(" /// <param name=\"serviceConsumer\">Reference to a MDSServiceConsumer object to send/receive MDS messages</param>");
classBuilder.AppendLine(" /// <param name=\"remoteEndPoint\">Remote application end point to send requests</param>");
classBuilder.AppendLine(" public " + proxyClassName + "(MDSServiceConsumer serviceConsumer, MDSRemoteAppEndPoint remoteEndPoint)");
classBuilder.AppendLine(" : base(serviceConsumer, remoteEndPoint, \"" + serviceType.Name + "\")");
classBuilder.AppendLine(" {");
classBuilder.AppendLine(" ");
classBuilder.AppendLine(" }");
classBuilder.AppendLine(" ");
classBuilder.AppendLine(" #endregion");
classBuilder.AppendLine(" ");
//Methods
classBuilder.AppendLine(" #region " + serviceType.Name + " methods");
classBuilder.AppendLine(" ");
foreach (var method in methods)
{
if (IsPredefinedMethod(method.Name))
{
continue;
}
WriteMethod(classBuilder, method);
}
classBuilder.AppendLine(" #endregion");
classBuilder.AppendLine(" ");
classBuilder.AppendLine(" #region Default (predefined) service methods");
classBuilder.AppendLine(" ");
foreach (var method in methods)
{
if (!IsPredefinedMethod(method.Name))
{
continue;
}
WriteMethod(classBuilder, method);
}
classBuilder.AppendLine(" #endregion");
//Close class
classBuilder.AppendLine(" }");
//Close namespace
classBuilder.AppendLine("}");
return classBuilder.ToString();
}
/// <summary>
/// This method can be used to check if service is available.
/// </summary>
/// <param name="message">A string message</param>
/// <returns>Reply to message as formatted: "RE:message".</returns>
[MDSServiceMethod(Description = "This method can be used to check if service is available.")]
[return: MDSServiceMethodParameter("Reply to message as formatted: 'RE: message'")]
public string CheckServiceIsAvailable([MDSServiceMethodParameter("A message to reply")] string message)
{
return ("RE: " + message);
}
#endregion
#region Private methods
private static void WriteMethod(StringBuilder classBuilder, MethodInfo method)
{
//Check for MDSServiceMethod attribute
var methodAttributes = method.GetCustomAttributes(typeof(MDSServiceMethodAttribute), true);
if (methodAttributes.Length <= 0)
{
return;
}
//Get MDSServiceMethod attribute
var serviceMethodAttribute = (MDSServiceMethodAttribute)methodAttributes[0];
//Get return type
var returnType = NormalizeType(method.ReturnType.Name);
//Get parameters
var parameters = method.GetParameters();
//Generate proxy method arguments and invoke method parameters
var methodArgumentsString = new StringBuilder();
var invokeParameters = new StringBuilder();
foreach (var parameter in parameters)
{
var paramType = NormalizeType(parameter.ParameterType.Name);
if (methodArgumentsString.Length > 0)
{
methodArgumentsString.Append(", ");
}
methodArgumentsString.Append(paramType + " " + parameter.Name);
invokeParameters.Append(", " + parameter.Name);
}
//Generate method summary
classBuilder.AppendLine(" /// <summary>");
classBuilder.AppendLine(" /// " + (serviceMethodAttribute.Description ?? "No method summary available."));
classBuilder.AppendLine(" /// </summary>");
//Generate XML-Comments for parameters
foreach (var parameter in parameters)
{
var paramAttributes = parameter.GetCustomAttributes(typeof(MDSServiceMethodParameterAttribute), true);
if (paramAttributes.Length <= 0)
{
continue;
}
classBuilder.AppendLine(" /// <param name=\"" + parameter.Name + "\">" + ((MDSServiceMethodParameterAttribute)paramAttributes[0]).Description + "</param>");
}
//Generate XML-Comments for return value
if (returnType != "void")
{
var returnAttributes = method.ReturnParameter.GetCustomAttributes(typeof(MDSServiceMethodParameterAttribute), true);
if (returnAttributes.Length > 0)
{
classBuilder.AppendLine(" /// <returns>" + ((MDSServiceMethodParameterAttribute)returnAttributes[0]).Description + "</returns>");
}
}
//Generate method signature and opening bracket
classBuilder.AppendLine(" public " + returnType + " " + method.Name + "(" + methodArgumentsString + ")");
classBuilder.AppendLine(" {");
//Generate method body according to return value
if (returnType == "void")
{
classBuilder.AppendLine(" InvokeRemoteMethod(\"" + method.Name + "\"" + invokeParameters + ");");
}
else
{
classBuilder.AppendLine(" return (" + returnType + ") InvokeRemoteMethodAndGetResult(\"" + method.Name + "\"" + invokeParameters + ");");
}
//Method closing bracket
classBuilder.AppendLine(" }");
classBuilder.AppendLine(" ");
}
/// <summary>
/// Normalizes some known primitive types.
/// </summary>
/// <param name="typeName">Type name</param>
/// <returns>Normalized type name</returns>
private static string NormalizeType(string typeName)
{
switch (typeName)
{
case "Void":
return "void";
case "Boolean":
return "bool";
case "Byte":
return "byte";
case "Byte[]":
return "byte[]";
case "Int16":
return "short";
case "Int16[]":
return "short[]";
case "Int32":
return "int";
case "Int32[]":
return "int[]";
case "Int64":
return "long";
case "Int64[]":
return "long[]";
case "String":
return "string";
case "String[]":
return "string[]";
case "Single":
return "float";
case "Single[]":
return "float[]";
case "Double":
return "double";
case "Double[]":
return "double[]";
}
//Not known type
return typeName;
}
/// <summary>
/// Checks if a method is predefined method (MDSService methods in MDSService class).
/// </summary>
/// <param name="methodName">Method name to check</param>
/// <returns>True: Yes, it is..</returns>
private static bool IsPredefinedMethod(string methodName)
{
return (methodName == "GenerateProxyClass" || methodName == "CheckServiceIsAvailable");
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I have started programming at 14 years old using Pascal as hobby. Then I interested in web development (HTML, JavaScript, ASP...) before university.
I graduated from Sakarya University Computer Engineering. At university, I learned C++, Visual Basic.NET, C#, ASP.NET and Java. I partly implemented ARP, IP and TCP protocols in Java as my final term project.
Now, I am working on Windows and web based software development mostly using Microsoft technologies in my own company.
My open source projects:
* ABP Framework:
https://abp.io
* jTable:
http://jtable.org
* Others:
https://github.com/hikalkan
My personal web site:
https://halilibrahimkalkan.com