Esempio n. 1
0
        static void Main(string[] args)
        {
            var map = new Dictionary<string, string>();
            var key = (string)null;
            foreach (var item in args)
            {
                if (item.Length == 0)
                    continue;
                if (item.StartsWith("-"))
                    key = item;
                else if (key != null)
                    map[key] = $"{(map.TryGetValue(key, out var value) ? value + " " : string.Empty)}{item.Trim(' ', '\'', '\"')}";
            }
            if (!map.TryGetValue("-p", out var path) && !map.TryGetValue("--path", out path))
            {
                throw new ArgumentException("Path missing, expect -p|--path path1 path2");
            }
            if (!map.TryGetValue("-o", out var output) && !map.TryGetValue("--out", out output))
            {
                throw new ArgumentException("Out missing, expect -o|--out path1 path2");
            }
            if (!map.TryGetValue("-n", out var nameSpace) && !map.TryGetValue("--namespace", out nameSpace))
            {
                //throw new ArgumentException("Nmaespace missing, expect -n|--namespace Name.Space");
            }
            CodeGeneratorMode mode = CodeGeneratorMode.Controllers;
            if (map.TryGetValue("-m", out var modeText) || map.TryGetValue("--mode", out modeText))
            {
                if (!Enum.TryParse<CodeGeneratorMode>(modeText, out mode))
                    throw new ArgumentException("Mode missing, expect -m|--mode Controllers|,|Logs|,|Invokers");
            }

            var generator = new CodeGenerator(path, output, nameSpace);
            generator.Mode = mode;
            generator.Generate();
            generator.GetUnits(true);

        }
        private void buildInterfaceCode(ICodeGeneratorContext codeGeneratorContext, InterfaceContract interfaceContract, out CodeTypeDeclaration codeType, out CodeNamespaceImportCollection imports)
        {
            IDictionary <XmlQualifiedName, string>    ElementName2TypeNameMapping = codeGeneratorContext.ElementName2TypeNameMapping;
            IDictionary <string, CodeTypeDeclaration> CodeTypeMap = codeGeneratorContext.CodeTypeMap;

            imports = new CodeNamespaceImportCollection();

            // generate service or client
            CodeGeneratorMode generatorMode = codeGeneratorContext.CodeGenOptions.CodeGeneratorMode;

            string interfaceName = "I" + interfaceContract.ServiceName.Replace("Interface", string.Empty);
            CodeTypeDeclaration interfaceType = new CodeTypeDeclaration(interfaceName);

            interfaceType.UserData.Add(Constants.GENERATED_TYPE, interfaceName);
            interfaceType.IsClass        = false;
            interfaceType.TypeAttributes = TypeAttributes.Public;
            interfaceType.IsInterface    = true;
            interfaceType.Comments.Clear();
            // Generate service documentation
            string serviceDoc = "Service interface auto-generated by SOA tool, DO NOT CHANGE!\n\n";

            serviceDoc += "注意,实现该接口的服务在AntServiceStack服务容器中是以new instance per request的形式被初始化的,\n";
            serviceDoc += "也就是说,容器会为每个请求创建一个新的服务实例,并在请求结束时释放(release),而不是单个\n";
            serviceDoc += "服务实例(singleton)服务所有的请求, 所以请务必不要在服务初始化(例如构造函数中)时做较重的初始化\n";
            serviceDoc += "(例如初始化数据库等)动作,否则对性能有很大影响,如果有较重的初始化动作,\n";
            serviceDoc += "请在服务实现中以静态方式(例如静态构造函数中)一次性完成,或者以IoC注入方式初始化,在服务容器\n";
            serviceDoc += "启动时事先将依赖初始化并注册在容器中,让容器在构造服务实例时自动解析和注入依赖(也可在服务实现中手动解析依赖),\n";
            serviceDoc += "关于静态和依赖注入初始化的样例,请参考AntServiceStack提供的样例程序.\n\n";

            if (!string.IsNullOrEmpty(interfaceContract.ServiceDocumentation))
            {
                serviceDoc += interfaceContract.ServiceDocumentation;
            }
            CodeDomHelper.CreateSummaryComment(interfaceType.Comments, serviceDoc);

            // Import AntServiceStack.ServiceHost namespace, requried by both client and service sides
            imports.Add(new CodeNamespaceImport(Constants.C_SERVICE_STACK_SERVICE_HOST_NAMESPACE));

            if (generatorMode == CodeGeneratorMode.Service)
            {
                // Mark as AntServiceStack supported service
                CodeAttributeDeclaration cServiceAttribute = new
                                                             CodeAttributeDeclaration("AntServiceInterface");

                string serviceName = interfaceContract.ServiceName;
                CodeAttributeArgument serviceNameArgument = new CodeAttributeArgument(new CodePrimitiveExpression(serviceName));
                cServiceAttribute.Arguments.Add(serviceNameArgument);

                string serviceNamespace = interfaceContract.ServiceNamespace;
                CodeAttributeArgument serviceNamespaceArgument = new CodeAttributeArgument(new CodePrimitiveExpression(serviceNamespace));
                cServiceAttribute.Arguments.Add(serviceNamespaceArgument);

                Version ver     = Assembly.GetExecutingAssembly().GetName().Version;
                string  version = ver.Major.ToString() + "." + ver.Minor.ToString() + "." +
                                  ver.Build.ToString() + "." + ver.Revision.ToString();
                CodeAttributeArgument codeGeneratorVersionArgument = new CodeAttributeArgument(new CodePrimitiveExpression(version));
                cServiceAttribute.Arguments.Add(codeGeneratorVersionArgument);
                interfaceType.CustomAttributes.Add(cServiceAttribute);
            }

            //CodeTypeDeclaration healthCheckRequestType = null;
            //CodeTypeDeclaration healthCheckResponseType = null;
            bool hasAsync = false;

            foreach (Operation operation in interfaceContract.OperationsCollection)
            {
                var isHealthCheckOperation = false;

                CodeMemberMethod method = new CodeMemberMethod();
                method.Name = operation.Name;
                if (operation.Name.ToLower() == HEALTH_CHECK_OPERATION_NAME.ToLower())
                {
                    isHealthCheckOperation = true;
                }

                Message          inMessage             = operation.Input;
                XmlQualifiedName inMessageElementQName = new XmlQualifiedName(inMessage.Element.ElementName, inMessage.Element.ElementNamespace);
                string           requestTypeName       = null;
                ElementName2TypeNameMapping.TryGetValue(inMessageElementQName, out requestTypeName);
                Enforce.IsNotNull <string>(requestTypeName, "Fail to retrieve request type from wsdl using innput message element QName : " + inMessageElementQName);

                CodeTypeReference requestTypeReference         = new CodeTypeReference(requestTypeName);
                CodeParameterDeclarationExpression methodParam =
                    new CodeParameterDeclarationExpression(requestTypeReference, "request");
                methodParam.Type = requestTypeReference;
                method.Parameters.Add(methodParam);

                Message outMessage = operation.Output;
                Enforce.IsNotNull <Message>(outMessage, "Fail to get out message in operation :  " + operation.Name + ", only requst/response style operation is supported");
                XmlQualifiedName outMessageElementQName = new XmlQualifiedName(outMessage.Element.ElementName, outMessage.Element.ElementNamespace);
                string           responseTypeName       = null;
                ElementName2TypeNameMapping.TryGetValue(outMessageElementQName, out responseTypeName);
                Enforce.IsNotNull <string>(responseTypeName, "Fail to retrieve response type from wsdl using output message element QName : " + outMessageElementQName);
                if (codeGeneratorContext.CodeGenOptions.GenerateAsyncOperations && outMessageElementQName.Name.EndsWith("AsyncResponse"))
                {
                    method.ReturnType = new CodeTypeReference("Task<" + responseTypeName + ">");
                    hasAsync          = true;
                }
                else
                {
                    method.ReturnType = new CodeTypeReference(responseTypeName);
                }

                //  SOA Policy enforcement : response type must extend SOA common AbstractResponseType
                CodeTypeDeclaration responseType = null;
                CodeTypeMap.TryGetValue(responseTypeName, out responseType);
                Enforce.IsNotNull <CodeTypeDeclaration>(responseType, "Weird code generator internal error, please ask soa framework team for help.");

                if (isHealthCheckOperation)
                {
                    //healthCheckResponseType = responseType;
                }

                if (!CodeExtension.HasProperty(responseType, Constants.RESPONSE_STATUS_PROPERTY_NAME, Constants.RESPONSE_STATUS_TYPE_NAME))
                {
                    throw new SOAPolicyViolationException(string.Format(" SOA Policy Violation, response type '{0}' does not include requried {1} property of type {2}",
                                                                        responseTypeName, Constants.RESPONSE_STATUS_PROPERTY_NAME, Constants.RESPONSE_STATUS_TYPE_NAME));
                }
                CodeTypeDeclaration responseStatusType = null;
                CodeTypeMap.TryGetValue(Constants.RESPONSE_STATUS_TYPE_NAME, out responseStatusType);
                Enforce.IsNotNull <CodeTypeDeclaration>(responseStatusType, string.Format("Weird code generator internal error, missing requried {0}, please ask soa framework team for help.", Constants.RESPONSE_STATUS_TYPE_NAME));
                if (!CodeExtension.IsSOACommonType(responseStatusType))
                {
                    throw new SOAPolicyViolationException(string.Format(" SOA Policy Violation, {0} reference is not  SOA Common {1}.", Constants.RESPONSE_STATUS_TYPE_NAME, Constants.RESPONSE_STATUS_TYPE_NAME));
                }

                if (!CodeExtension.HasInterface(responseType, HAS_RESPONSE_STATUS_INTERFACE_NAME))
                {
                    // make response type implement IHasResponseStatus interface
                    responseType.BaseTypes.Add(HAS_RESPONSE_STATUS_INTERFACE_NAME);
                }

                // optional common request handling
                CodeTypeDeclaration requestType = null;
                CodeTypeMap.TryGetValue(requestTypeName, out requestType);
                Enforce.IsNotNull <CodeTypeDeclaration>(requestType, "Weird code generator internal error, please ask soa framework team for help.");

                if (isHealthCheckOperation)
                {
                    //healthCheckRequestType = requestType;
                }

                if (CodeExtension.HasProperty(requestType, MOBILE_REQUEST_HEAD_PROPERTY_NAME, MOBILE_REQUEST_HEAD_TYPE_NAME) &&
                    !CodeExtension.HasInterface(requestType, HAS_MOBILE_REQUEST_HEAD_INTERFACE_NAME))
                {
                    requestType.BaseTypes.Add(HAS_MOBILE_REQUEST_HEAD_INTERFACE_NAME);
                }

                if (CodeExtension.HasProperty(responseType, Constants.COMMON_REQUEST_PROPERTY_NAME, Constants.COMMON_REQUEST_TYPE_NAME))
                {
                    CodeTypeDeclaration commonRequestType = null;
                    CodeTypeMap.TryGetValue(Constants.COMMON_REQUEST_TYPE_NAME, out commonRequestType);
                    Enforce.IsNotNull <CodeTypeDeclaration>(commonRequestType, string.Format("Weird code generator internal error, missing requried {0}, please ask soa framework team for help.", Constants.COMMON_REQUEST_TYPE_NAME));
                    if (!CodeExtension.IsSOACommonType(commonRequestType))
                    {
                        throw new SOAPolicyViolationException(string.Format(" SOA Policy Violation, {0} reference is not Ant SOA Common {1}.", Constants.COMMON_REQUEST_TYPE_NAME, Constants.COMMON_REQUEST_TYPE_NAME));
                    }
                    if (!CodeExtension.HasInterface(responseType, HAS_COMMON_REQUEST_INTERFACE_NAME))
                    {
                        // make request type implement IHasCommonRequest interface
                        responseType.BaseTypes.Add(HAS_COMMON_REQUEST_INTERFACE_NAME);
                    }
                }

                // Generate operation documentation
                if (!string.IsNullOrEmpty(operation.Documentation))
                {
                    CodeDomHelper.CreateSummaryComment(method.Comments, operation.Documentation);
                }

                interfaceType.Members.Add(method);
            }

            if (hasAsync)
            {
                imports.Add(new CodeNamespaceImport(Constants.SYSTEM_THREADING_TASKS_NAMESPACE));
            }

            // SOA Policy enforcement : healtch check operation is mandatory
            //if (healthCheckRequestType == null || healthCheckResponseType == null)
            //{
            //    throw new SOAPolicyViolationException(string.Format("SOA Policy Violation, missing mandatory check health operation."));
            //}
            //if (!CodeExtension.IsSOACommonType(healthCheckRequestType) || !CodeExtension.IsSOACommonType(healthCheckResponseType))
            //{
            //    throw new SOAPolicyViolationException(string.Format("SOA Policy Violation, wrong SOA common healthcheck types."));
            //}

            if (generatorMode == CodeGeneratorMode.Service)
            {
                codeType = interfaceType;
                return;
            }

            imports.Add(new CodeNamespaceImport(SYSTEM_NAMESPACE));
            imports.Add(new CodeNamespaceImport(SYSTEM_THREADING_NAMESPACE));
            imports.Add(new CodeNamespaceImport(SYSTEM_THREADING_TASKS_NAMESPACE));
            imports.Add(new CodeNamespaceImport(
                            generatorMode == CodeGeneratorMode.Client ? C_SERVICE_STACK_SERVICE_CLIENT_NAMESPACE : C_SERVICE_STACK_AUTOMATION_TEST_CLIENT_NAMESPACE));

            string clientName = interfaceContract.ServiceName.Replace("Interface", string.Empty) + "Client";

            CodeTypeDeclaration clientType = new CodeTypeDeclaration(clientName);

            clientType.UserData.Add(Constants.GENERATED_TYPE, clientName);
            var baseType = new CodeTypeReference(
                generatorMode == CodeGeneratorMode.Client ? SERVICE_CLIENT_BASE_NAME : SERVICE_CLIENT_FOR_AUTOMATION_BASE_NAME,
                new CodeTypeReference[] { new CodeTypeReference(clientName) });

            clientType.BaseTypes.Add(baseType);
            codeType = clientType;

            // Generate client documentation
            string clientDoc = "Service client auto-generated by SOA tool, DO NOT CHANGE!\n\n";

            if (!string.IsNullOrEmpty(interfaceContract.ServiceDocumentation))
            {
                clientDoc += interfaceContract.ServiceDocumentation;
            }
            CodeDomHelper.CreateSummaryComment(clientType.Comments, clientDoc);

            // base constructor
            //CodeConstructor baseConstructor = new CodeConstructor();
            //baseConstructor.Attributes = MemberAttributes.Public;
            //baseConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(""));
            //clientType.Members.Add(baseConstructor);

            // public constant string service name and namespace
            CodeMemberField codeMemberField = new CodeMemberField(typeof(string), SERVICE_CLIENT_CODE_GENERATOR_VERSION_FIELD_NAME);

            codeMemberField.Attributes     = (codeMemberField.Attributes & ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask) | MemberAttributes.Public | MemberAttributes.Const;
            codeMemberField.InitExpression = new CodePrimitiveExpression(typeof(InterfaceContractGenerator).Assembly.GetName().Version.ToString());
            clientType.Members.Add(codeMemberField);
            codeMemberField                = new CodeMemberField(typeof(string), SERVICE_CLIENT_ORIGINAL_SERVICE_NAME_FIELD_NAME);
            codeMemberField.Attributes     = (codeMemberField.Attributes & ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask) | MemberAttributes.Public | MemberAttributes.Const;
            codeMemberField.InitExpression = new CodePrimitiveExpression(interfaceContract.ServiceName);
            clientType.Members.Add(codeMemberField);
            codeMemberField                = new CodeMemberField(typeof(string), SERVICE_CLIENT_ORIGINAL_SERVICE_NAMESPACE_FIELD_NAME);
            codeMemberField.Attributes     = (codeMemberField.Attributes & ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask) | MemberAttributes.Public | MemberAttributes.Const;
            codeMemberField.InitExpression = new CodePrimitiveExpression(interfaceContract.ServiceNamespace);
            clientType.Members.Add(codeMemberField);
            codeMemberField                = new CodeMemberField(typeof(string), SERVICE_CLIENT_ORIGINAL_SERVICE_TYPE_FIELD_NAME);
            codeMemberField.Attributes     = (codeMemberField.Attributes & ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask) | MemberAttributes.Public | MemberAttributes.Const;
            codeMemberField.InitExpression = new CodePrimitiveExpression(SERVICE_CLIENT_NON_SLB_SERVICE_TYPE_FIELD_NAME);
            clientType.Members.Add(codeMemberField);

            // private constructor with baseUri parameter
            CodeConstructor baseConstructorWithParameter = new CodeConstructor();

            baseConstructorWithParameter.Attributes = MemberAttributes.Private;
            baseConstructorWithParameter.Parameters.Add(new CodeParameterDeclarationExpression("System.String", "baseUri"));
            baseConstructorWithParameter.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("baseUri"));
            clientType.Members.Add(baseConstructorWithParameter);

            // private constructor with serviceName & serviceNamespace parameter
            baseConstructorWithParameter            = new CodeConstructor();
            baseConstructorWithParameter.Attributes = MemberAttributes.Private;
            baseConstructorWithParameter.Parameters.Add(new CodeParameterDeclarationExpression("System.String", "serviceName"));
            baseConstructorWithParameter.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("serviceName"));
            baseConstructorWithParameter.Parameters.Add(new CodeParameterDeclarationExpression("System.String", "serviceNamespace"));
            baseConstructorWithParameter.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("serviceNamespace"));
            baseConstructorWithParameter.Parameters.Add(new CodeParameterDeclarationExpression("System.String", "subEnv"));
            baseConstructorWithParameter.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("subEnv"));
            clientType.Members.Add(baseConstructorWithParameter);

            // build methods
            foreach (Operation operation in interfaceContract.OperationsCollection)
            {
                string           operationName         = operation.Name;
                Message          inMessage             = operation.Input;
                XmlQualifiedName inMessageElementQName = new XmlQualifiedName(inMessage.Element.ElementName, inMessage.Element.ElementNamespace);
                string           requestTypeName       = null;
                ElementName2TypeNameMapping.TryGetValue(inMessageElementQName, out requestTypeName);
                Message          outMessage             = operation.Output;
                XmlQualifiedName outMessageElementQName = new XmlQualifiedName(outMessage.Element.ElementName, outMessage.Element.ElementNamespace);
                string           responseTypeName       = null;
                ElementName2TypeNameMapping.TryGetValue(outMessageElementQName, out responseTypeName);
                CodeTypeReference responseType = new CodeTypeReference(responseTypeName);

                BuildSyncMethod(clientType, operation, requestTypeName, responseTypeName);
                BuildSyncWithCallbackMethod(clientType, operation, requestTypeName, responseTypeName);
                BuildCreateRequestTaskMethod(clientType, operation, requestTypeName, responseTypeName);
                BuildStartIOCPTaskMethod(clientType, operation, requestTypeName, responseTypeName);
            }
        }