Example #1
0
        public void CorrectlyReferencedServicesShouldBeIncludedInSMD()
        {
            var xmlDocSource = new XmlDocSource();

            xmlDocSource.Dtos.Add(AssemblyWithXmlDocs.CreateFromName("TestAssembly.DTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "."));
            xmlDocSource.RouteAssembly = AssemblyWithXmlDocs.CreateFromName("TestAssembly.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", ".");
            xmlDocSource.Routes        = new List <RouteElement> {
                new RouteElement {
                    Endpoint = "/session",
                    Name     = "session",
                    Type     = "TestAssembly.Service.ITestService, TestAssembly.Service, Version=1.0.0.0"
                },
                new RouteElement {
                    Endpoint = "/session",
                    Name     = "session_logout",
                    Type     = "TestAssembly.Service.ITestService, TestAssembly.Service, Version=1.0.0.0"
                }
            };

            var jsonSchema = new JsonSchemaDtoEmitter().EmitDtoJson(xmlDocSource);
            var smdSchema  = new WcfSMD.Emitter().EmitSmdJson(xmlDocSource, true, jsonSchema);

            Console.WriteLine(smdSchema.SMD);
            Assert.That(smdSchema.SMD["services"]["rpc"]["services"]["CreateSession"], Is.Not.Null);
            Assert.That(smdSchema.SMD["services"]["rpc"]["services"]["DeleteSession"], Is.Not.Null);
        }
        public MetadataGenerationResult EmitSmdJson(XmlDocSource xmlDocSource, bool includeDemoValue, JObject schema)
        {
            var result = new MetadataGenerationResult();
            JObject smd = new JObject
                              {
                                  {"SMDVersion","2.6"},
                                  {"version",xmlDocSource.RouteAssembly.Version},
                                  {"description","CIAPI SMD"},
                                  {"services", new JObject()}
                              };

            var rpc = new JObject();
            smd["services"]["rpc"] = rpc;
            rpc["target"] = "";
            JObject rpcServices = new JObject();
            rpc["services"] = rpcServices;

            var seenTypes = new List<Type>(); // just to keep track of types so we don't map twice

            foreach (RouteElement route in xmlDocSource.Routes)
            {
                var serviceResult = BuildServiceMapping(xmlDocSource, route, seenTypes, rpcServices, includeDemoValue, schema);
                result.AddValidationResults(serviceResult);
            }

            result.SMD = smd;
            return result;
        }
        public MetadataValidationResult AuditTypes(XmlDocSource xmlDocSource)
        {
            var results = new MetadataValidationResult();
            foreach (var assembly in xmlDocSource.Dtos.Select(a => a.Assembly))
            {
                foreach (Type type in assembly.GetTypes())
                {
                    // we don't emit interfaces
                    if (type.IsInterface)
                    {
                        continue;
                    }

                    try
                    {
                        AuditType(type, false);
                        results.AddMetadataGenerationSuccess(new MetadataGenerationSuccess(MetadataType.JsonSchema, type));
                    }
                    catch (MetadataValidationException e)
                    {
                        results.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.JsonSchema, type, e));
                    }
                }
            }
            return results;
        }
Example #4
0
        public MetadataValidationResult AuditTypes(XmlDocSource xmlDocSource)
        {
            var results = new MetadataValidationResult();

            foreach (var assembly in xmlDocSource.Dtos.Select(a => a.Assembly))
            {
                foreach (Type type in assembly.GetTypes())
                {
                    // we don't emit interfaces
                    if (type.IsInterface)
                    {
                        continue;
                    }

                    try
                    {
                        AuditType(type, false);
                        results.AddMetadataGenerationSuccess(new MetadataGenerationSuccess(MetadataType.JsonSchema, type));
                    }
                    catch (MetadataValidationException e)
                    {
                        results.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.JsonSchema, type, e));
                    }
                }
            }
            return(results);
        }
Example #5
0
        public MetadataGenerationResult EmitSmdJson(XmlDocSource xmlDocSource, bool includeDemoValue, JObject schema)
        {
            var     result = new MetadataGenerationResult();
            JObject smd    = new JObject
            {
                { "SMDVersion", "2.6" },
                { "version", xmlDocSource.RouteAssembly.Version },
                { "description", "CIAPI SMD" },
                { "services", new JObject() }
            };

            var rpc = new JObject();

            smd["services"]["rpc"] = rpc;
            rpc["target"]          = "";
            JObject rpcServices = new JObject();

            rpc["services"] = rpcServices;

            var seenTypes = new List <Type>(); // just to keep track of types so we don't map twice

            foreach (RouteElement route in xmlDocSource.Routes)
            {
                var serviceResult = BuildServiceMapping(xmlDocSource, route, seenTypes, rpcServices, includeDemoValue, schema);
                result.AddValidationResults(serviceResult);
            }

            result.SMD = smd;
            return(result);
        }
 protected static XmlDocSource CreateXmlDocSourceForTestAssembly(List<RouteElement> routes)
 {
     var xmlDocSource = new XmlDocSource();
     xmlDocSource.Dtos.Add(AssemblyWithXmlDocs.CreateFromName("TestAssembly.DTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "."));
     xmlDocSource.RouteAssembly = AssemblyWithXmlDocs.CreateFromName("TestAssembly.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", ".");
     xmlDocSource.Routes = routes;
     return xmlDocSource;
 }
Example #7
0
        protected static XmlDocSource CreateXmlDocSourceForTestAssembly(List <RouteElement> routes)
        {
            var xmlDocSource = new XmlDocSource();

            xmlDocSource.Dtos.Add(AssemblyWithXmlDocs.CreateFromName("TestAssembly.DTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "."));
            xmlDocSource.RouteAssembly = AssemblyWithXmlDocs.CreateFromName("TestAssembly.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", ".");
            xmlDocSource.Routes        = routes;
            return(xmlDocSource);
        }
        public void AllArrayTypesShouldValidate()
        {
            var xmlDocSource = new XmlDocSource();
            xmlDocSource.Dtos.Add(AssemblyWithXmlDocs.CreateFromName("TestAssembly.DTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", @"TestData\valid"));

            var result = new Auditor().AuditTypes(xmlDocSource);

            result.MetadataGenerationErrors.ForEach(e => Console.WriteLine(e.ToString()));
            Assert.AreEqual(0, result.MetadataGenerationErrors.Count, "No errors should have been reported");
        }
        public void AllArrayTypesShouldValidate()
        {
            var xmlDocSource = new XmlDocSource();

            xmlDocSource.Dtos.Add(AssemblyWithXmlDocs.CreateFromName("TestAssembly.DTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", @"TestData\valid"));

            var result = new Auditor().AuditTypes(xmlDocSource);

            result.MetadataGenerationErrors.ForEach(e => Console.WriteLine(e.ToString()));
            Assert.AreEqual(0, result.MetadataGenerationErrors.Count, "No errors should have been reported");
        }
        private JObject GenerateJsonSchemaForTestAssemblyDTO()
        {
            var xmlDocSource = new XmlDocSource();

            xmlDocSource.Dtos.Add(AssemblyWithXmlDocs.CreateFromName("TestAssembly.DTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", @"TestData\valid"));
            xmlDocSource.RouteAssembly = new AssemblyWithXmlDocs()
            {
                Version = "1.0.0.0"
            };
            return(new JsonSchemaDtoEmitter().EmitDtoJson(xmlDocSource));
        }
        public void Context()
        {
            _xmlDocSource = CreateXmlDocSourceForTestAssembly(
               new List<RouteElement>{
                  new RouteElement {
                                    Endpoint = ENDPOINT1,
                                    Name = "GetDetail",
                                    Type = "TestAssembly.Service.ISimpleService, TestAssembly.Service, Version=1.0.0.0"}
                  ,
            });

            _jsonSchema = new JsonSchemaDtoEmitter().EmitDtoJson(_xmlDocSource);
            _smdSchema = new WcfSMD.Emitter().EmitSmdJson(_xmlDocSource, true, _jsonSchema);
        }
Example #12
0
        public void Context()
        {
            _xmlDocSource = CreateXmlDocSourceForTestAssembly(
                new List <RouteElement> {
                new RouteElement {
                    Endpoint = ENDPOINT1,
                    Name     = "GetDetail",
                    Type     = "TestAssembly.Service.ISimpleService, TestAssembly.Service, Version=1.0.0.0"
                }
                ,
            });

            _jsonSchema = new JsonSchemaDtoEmitter().EmitDtoJson(_xmlDocSource);
            _smdSchema  = new WcfSMD.Emitter().EmitSmdJson(_xmlDocSource, true, _jsonSchema);
        }
        public void CorrectlyReferencedServicesShouldBeIncludedInSMD()
        {
            var xmlDocSource = new XmlDocSource();
            xmlDocSource.Dtos.Add(AssemblyWithXmlDocs.CreateFromName("TestAssembly.DTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "."));
            xmlDocSource.RouteAssembly = AssemblyWithXmlDocs.CreateFromName("TestAssembly.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", ".");
            xmlDocSource.Routes = new List<RouteElement>{
                new RouteElement {
                    Endpoint = "/session",
                    Name = "session",
                    Type = "TestAssembly.Service.ITestService, TestAssembly.Service, Version=1.0.0.0"},
                new RouteElement {
                    Endpoint = "/session",
                    Name = "session_logout",
                    Type = "TestAssembly.Service.ITestService, TestAssembly.Service, Version=1.0.0.0"}
            };

            var jsonSchema = new JsonSchemaDtoEmitter().EmitDtoJson(xmlDocSource);
            var smdSchema = new WcfSMD.Emitter().EmitSmdJson(xmlDocSource, true, jsonSchema);

            Console.WriteLine(smdSchema.SMD);
            Assert.That(smdSchema.SMD["services"]["rpc"]["services"]["CreateSession"], Is.Not.Null);
            Assert.That(smdSchema.SMD["services"]["rpc"]["services"]["DeleteSession"], Is.Not.Null);
        }
 private JObject GenerateJsonSchemaForTestAssemblyDTO()
 {
     var xmlDocSource = new XmlDocSource();
     xmlDocSource.Dtos.Add(AssemblyWithXmlDocs.CreateFromName("TestAssembly.DTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", @"TestData\valid"));
     xmlDocSource.RouteAssembly = new AssemblyWithXmlDocs() { Version = "1.0.0.0" };
     return new JsonSchemaDtoEmitter().EmitDtoJson(xmlDocSource);
 }
        public JObject EmitDtoJson(XmlDocSource xmlDocSource)
        {
            var schemaObj = new JObject();
            var assemblies = xmlDocSource.Dtos.Select(a => a.Assembly).ToArray();

            schemaObj["version"] = xmlDocSource.RouteAssembly.Version;
            var schemaProperties = new JObject();
            schemaObj["properties"] = schemaProperties;

            var types = UtilityExtensions.GetSchemaTypes(assemblies);
            var exception = new MetadataValidationException(typeof (object), "", "Errors generating meta for types", "");
            foreach (Type type in types)
            {
                try
                {

                    var typeNode = type.GetXmlDocTypeNodeWithJSchema();
                    var jschemaXml =
                        JschemaXmlComment.CreateFromXml(typeNode.XPathSelectElement("jschema"));

                    if (jschemaXml.Exclude)
                        continue; //Skip to next type

                    var typeObj = new JObject();
                    typeObj["id"] = type.Name;

                    if (type.IsEnum)
                    {
                        RenderEnum(type, typeObj);
                    }
                    else if (type.IsClass)
                    {
                        RenderType(type, typeObj);
                    }
                    else
                    {
                        throw new NotSupportedException(type.Name + " is not supported ");
                    }

                    ApplyDescription(typeObj, typeNode);

                    if (jschemaXml.DemoValue != null)
                    {
                        typeObj["demoValue"] = jschemaXml.DemoValue;
                    }

                    schemaProperties.Add(type.Name, typeObj);
                }
                catch (MetadataValidationException ex)
                {
                    exception.AggregatedExceptions.Add(ex);
                }

            }

            if (exception.AggregatedExceptions.Count>0)
            {
                throw exception;
            }
            return schemaObj;
        }
Example #16
0
        private MetadataValidationResult BuildServiceMapping(XmlDocSource xmlDocSource, RouteElement route, List <Type> seenTypes, JObject smdBase, bool includeDemoValue, JObject schema)
        {
            var result = new MetadataValidationResult();

            Type type = xmlDocSource.RouteAssembly.Assembly.GetType(route.Type.Substring(0, route.Type.IndexOf(",")));

            if (seenTypes.Contains(type))
            {
                return(result);
            }

            seenTypes.Add(type);

            var typeElement = type.GetXmlDocTypeNodeWithSMD();

            if (typeElement == null)
            {
                return(result);
            }

            var methodTarget = route.Endpoint.Trim('/');

            foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance))
            {
                var methodElement = type.GetXmlDocMemberNodeWithSMD(type.FullName + "." + method.Name);
                if (methodElement == null)
                {
                    continue;
                }

                // get smd xml, if present
                var methodSmdElement = methodElement.XPathSelectElement("smd");
                if (methodSmdElement == null)
                {
                    result.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.SMD, type, "should not have gotten a method element without smd", "All services that have XML comments must have a <smd> tag.  See https://github.com/cityindex/RESTful-Webservice-Schema/wiki/Howto-write-XML-comments-for-SMD for details"));
                    continue; //advance to next service method
                }

                var smdXmlComment = SmdXmlComment.CreateFromXml(methodSmdElement);

                //Don't document methods that are marked exclude
                if (smdXmlComment.Exclude)
                {
                    continue; //advance to next service method
                }
                JObject service    = null;
                var     opContract = ReflectionUtils.GetAttribute <OperationContractAttribute>(method);

                if (opContract != null)
                {
                    var webGet     = ReflectionUtils.GetAttribute <WebGetAttribute>(method);
                    var methodName = method.Name;
                    if (!string.IsNullOrEmpty(smdXmlComment.MethodName))
                    {
                        methodName = smdXmlComment.MethodName;
                    }

                    string methodTransport   = null;
                    string methodEnvelope    = null;
                    string methodUriTemplate = null;

                    if (webGet != null)
                    {
                        service           = new JObject();
                        methodUriTemplate = ResolveUriTemplate(smdXmlComment, webGet.UriTemplate);
                        methodTransport   = "GET";
                        methodEnvelope    = "URL";
                    }
                    else
                    {
                        var webInvoke = ReflectionUtils.GetAttribute <WebInvokeAttribute>(method);
                        if (webInvoke != null)
                        {
                            service           = new JObject();
                            methodUriTemplate = ResolveUriTemplate(smdXmlComment, webInvoke.UriTemplate);

                            switch (webInvoke.Method.ToUpper())
                            {
                            case "POST":
                                methodTransport = "POST";
                                methodEnvelope  = "JSON";
                                break;

                            case "GET":
                                methodTransport = "GET";
                                methodEnvelope  = "URL";
                                break;

                            default:
                                result.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.SMD, type,
                                                                                              string.Format("The {0} service has transport method of type {1} that is not supported", methodName, webInvoke.Method), "Service transports like DELETE or PUT are poorly supported by client http clients, so you advised to only use GET or POST"));
                                continue;     //advance to next service method
                            }
                        }
                    }

                    if (service != null)
                    {
                        JsonSchemaUtilities.ApplyDescription(service, methodElement);

                        service.Add("target", ResolveEndpoint(smdXmlComment, methodTarget));

                        if (!string.IsNullOrWhiteSpace(methodUriTemplate))
                        {
                            service.Add("uriTemplate", methodUriTemplate);
                        }
                        service.Add("contentType", "application/json");         // TODO: declare this in meta or get from WebGet/WebInvoke
                        service.Add("responseContentType", "application/json"); // TODO: declare this in meta or get from WebGet/WebInvoke
                        service.Add("transport", methodTransport);

                        try
                        {
                            smdBase.Add(methodName, service);
                        }
                        catch (ArgumentException e)
                        {
                            result.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.SMD, type, string.Format("A service with the method name {0} already exists", methodName), "Ensure that methods names are unique across services"));
                            return(result);
                        }

                        // this is not accurate/valid SMD for GET but dojox.io.services is not, yet, a very good
                        // implementation of the SMD spec, which is funny as they were both written by the same person.
                        service.Add("envelope", methodEnvelope);

                        // determine if return type is object or primitive
                        JObject returnType = null;
                        if (Type.GetTypeCode(method.ReturnType) == TypeCode.Object)
                        {
                            if (method.ReturnType.Name != "Void")
                            {
                                string methodReturnTypeName = method.ReturnType.Name;
                                if (schema["properties"][methodReturnTypeName] == null)
                                {
                                    result.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.SMD, type, "Schema missing referenced return type " + methodReturnTypeName + " for method " + method.Name, "All types used by services must be decorated with the <jschema> tag.  See https://github.com/cityindex/RESTful-Webservice-Schema/wiki/Howto-write-XML-comments-for-JSchema"));
                                }
                                returnType = new JObject(new JProperty("$ref", JsonSchemaUtilities.RootDelimiter + methodReturnTypeName));
                            }
                            else
                            {
                                returnType = null;
                            }
                        }
                        else if (Type.GetTypeCode(method.ReturnType) == TypeCode.Empty)
                        {
                            returnType = null;
                        }
                        else
                        {
                            returnType = new JObject(new JProperty("type", method.ReturnType.GetSchemaType()["type"].Value <string>()));
                        }
                        if (returnType != null)
                        {
                            service.Add("returns", returnType);
                        }

                        SetStringAttribute(methodSmdElement, service, "group");
                        SetIntAttribute(methodSmdElement, service, "cacheDuration");
                        SetStringAttribute(methodSmdElement, service, "throttleScope");

                        var paramResult = AddParameters(type, method, methodElement, service, includeDemoValue, schema);
                        if (paramResult.HasErrors)
                        {
                            result.AddMetadataGenerationErrors(paramResult.MetadataGenerationErrors);
                        }
                    }
                }
                if (!result.HasErrors)
                {
                    result.AddMetadataGenerationSuccess(new MetadataGenerationSuccess(MetadataType.SMD, type));
                }
            }

            return(result);
        }
Example #17
0
        private MetadataValidationResult BuildServiceMapping(XmlDocSource xmlDocSource, RouteElement route, List<Type> seenTypes, JObject smdBase, bool includeDemoValue, JObject schema)
        {
            var result = new MetadataValidationResult();

            Type type = xmlDocSource.RouteAssembly.Assembly.GetType(route.Type.Substring(0, route.Type.IndexOf(",")));
            if (seenTypes.Contains(type))
            {
                return result;
            }

            seenTypes.Add(type);

            var typeElement = type.GetXmlDocTypeNodeWithSMD();

            if (typeElement == null)
            {
                return result;
            }

            var methodTarget = route.Endpoint.Trim('/');

            foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance))
            {
                var methodElement = type.GetXmlDocMemberNodeWithSMD(type.FullName + "." + method.Name);
                if (methodElement == null)
                {
                    continue;
                }

                // get smd xml, if present
                var methodSmdElement = methodElement.XPathSelectElement("smd");
                if (methodSmdElement == null)
                {
                    result.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.SMD, type, "should not have gotten a method element without smd", "All services that have XML comments must have a <smd> tag.  See https://github.com/cityindex/RESTful-Webservice-Schema/wiki/Howto-write-XML-comments-for-SMD for details"));
                    continue; //advance to next service method
                }

                var smdXmlComment = SmdXmlComment.CreateFromXml(methodSmdElement);

                //Don't document methods that are marked exclude
                if (smdXmlComment.Exclude)
                    continue; //advance to next service method

                JObject service = null;
                var opContract = ReflectionUtils.GetAttribute<OperationContractAttribute>(method);

                if (opContract != null)
                {
                    var webGet = ReflectionUtils.GetAttribute<WebGetAttribute>(method);
                    var methodName = method.Name;
                    if (!string.IsNullOrEmpty(smdXmlComment.MethodName))
                        methodName = smdXmlComment.MethodName;

                    string methodTransport = null;
                    string methodEnvelope = null;
                    string methodUriTemplate = null;

                    if (webGet != null)
                    {
                        service = new JObject();
                        methodUriTemplate = ResolveUriTemplate(smdXmlComment, webGet.UriTemplate);
                        methodTransport = "GET";
                        methodEnvelope = "URL";
                    }
                    else
                    {
                        var webInvoke = ReflectionUtils.GetAttribute<WebInvokeAttribute>(method);
                        if (webInvoke != null)
                        {
                            service = new JObject();
                            methodUriTemplate = ResolveUriTemplate(smdXmlComment, webInvoke.UriTemplate);

                            switch (webInvoke.Method.ToUpper())
                            {
                                case "POST":
                                    methodTransport = "POST";
                                    methodEnvelope = "JSON";
                                    break;
                                case "GET":
                                    methodTransport = "GET";
                                    methodEnvelope = "URL";
                                    break;
                                default:
                                    result.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.SMD, type,
                                        string.Format("The {0} service has transport method of type {1} that is not supported", methodName, webInvoke.Method), "Service transports like DELETE or PUT are poorly supported by client http clients, so you advised to only use GET or POST"));
                                    continue; //advance to next service method
                            }

                        }
                    }

                    if (service != null)
                    {
                        JsonSchemaUtilities.ApplyDescription(service, methodElement);

                        service.Add("target", ResolveEndpoint(smdXmlComment, methodTarget));

                        if (!string.IsNullOrWhiteSpace(methodUriTemplate))
                        {
                            service.Add("uriTemplate", methodUriTemplate);
                        }
                        service.Add("contentType", "application/json");// TODO: declare this in meta or get from WebGet/WebInvoke
                        service.Add("responseContentType", "application/json");// TODO: declare this in meta or get from WebGet/WebInvoke
                        service.Add("transport", methodTransport);

                        try
                        {
                            smdBase.Add(methodName, service);
                        }
                        catch (ArgumentException e)
                        {
                            result.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.SMD, type, string.Format("A service with the method name {0} already exists", methodName), "Ensure that methods names are unique across services"));
                            return result;
                        }

                        // this is not accurate/valid SMD for GET but dojox.io.services is not, yet, a very good
                        // implementation of the SMD spec, which is funny as they were both written by the same person.
                        service.Add("envelope", methodEnvelope);

                        // determine if return type is object or primitive
                        JObject returnType = null;
                        if (Type.GetTypeCode(method.ReturnType) == TypeCode.Object)
                        {
                            if (method.ReturnType.Name != "Void")
                            {
                                string methodReturnTypeName = method.ReturnType.Name;
                                if (schema["properties"][methodReturnTypeName] == null)
                                {
                                    result.AddMetadataGenerationError(new MetadataGenerationError(MetadataType.SMD, type, "Schema missing referenced return type " + methodReturnTypeName + " for method " + method.Name, "All types used by services must be decorated with the <jschema> tag.  See https://github.com/cityindex/RESTful-Webservice-Schema/wiki/Howto-write-XML-comments-for-JSchema"));
                                }
                                returnType = new JObject(new JProperty("$ref", JsonSchemaUtilities.RootDelimiter + methodReturnTypeName));
                            }
                            else
                            {
                                returnType = null;
                            }

                        }
                        else if (Type.GetTypeCode(method.ReturnType) == TypeCode.Empty)
                        {
                            returnType = null;

                        }
                        else
                        {
                            returnType = new JObject(new JProperty("type", method.ReturnType.GetSchemaType()["type"].Value<string>()));
                        }
                        if (returnType != null)
                        {
                            service.Add("returns", returnType);
                        }

                        SetStringAttribute(methodSmdElement, service, "group");
                        SetIntAttribute(methodSmdElement, service, "cacheDuration");
                        SetStringAttribute(methodSmdElement, service, "throttleScope");

                        var paramResult = AddParameters(type, method, methodElement, service, includeDemoValue, schema);
                        if (paramResult.HasErrors)
                            result.AddMetadataGenerationErrors(paramResult.MetadataGenerationErrors);
                    }

                }
                if (!result.HasErrors)
                    result.AddMetadataGenerationSuccess(new MetadataGenerationSuccess(MetadataType.SMD, type));
            }

            return result;
        }
        public JObject EmitDtoJson(XmlDocSource xmlDocSource)
        {
            var schemaObj  = new JObject();
            var assemblies = xmlDocSource.Dtos.Select(a => a.Assembly).ToArray();


            schemaObj["version"] = xmlDocSource.RouteAssembly.Version;
            var schemaProperties = new JObject();

            schemaObj["properties"] = schemaProperties;

            var types     = UtilityExtensions.GetSchemaTypes(assemblies);
            var exception = new MetadataValidationException(typeof(object), "", "Errors generating meta for types", "");

            foreach (Type type in types)
            {
                try
                {
                    var typeNode   = type.GetXmlDocTypeNodeWithJSchema();
                    var jschemaXml =
                        JschemaXmlComment.CreateFromXml(typeNode.XPathSelectElement("jschema"));

                    if (jschemaXml.Exclude)
                    {
                        continue; //Skip to next type
                    }
                    var typeObj = new JObject();
                    typeObj["id"] = type.Name;

                    if (type.IsEnum)
                    {
                        RenderEnum(type, typeObj);
                    }
                    else if (type.IsClass)
                    {
                        RenderType(type, typeObj);
                    }
                    else
                    {
                        throw new NotSupportedException(type.Name + " is not supported ");
                    }

                    ApplyDescription(typeObj, typeNode);

                    if (jschemaXml.DemoValue != null)
                    {
                        typeObj["demoValue"] = jschemaXml.DemoValue;
                    }

                    schemaProperties.Add(type.Name, typeObj);
                }
                catch (MetadataValidationException ex)
                {
                    exception.AggregatedExceptions.Add(ex);
                }
            }

            if (exception.AggregatedExceptions.Count > 0)
            {
                throw exception;
            }
            return(schemaObj);
        }