public Metadata Generate()
        {
            var httpConfiguration = new HttpConfiguration();

            var constraintResolver = new DefaultInlineConstraintResolver();
            constraintResolver.ConstraintMap.Add("idorcurrent", typeof(IdOrCurrentConstraint));
            constraintResolver.ConstraintMap.Add("deviceGuid", typeof(DeviceGuidConstraint));
            httpConfiguration.MapHttpAttributeRoutes(constraintResolver);

            httpConfiguration.EnsureInitialized();

            var apiExplorer = httpConfiguration.Services.GetApiExplorer();
            var metadata = new Metadata
            {
                Resources = apiExplorer.ApiDescriptions
                    .OrderBy(d => d.ActionDescriptor.ControllerDescriptor.ControllerName)
                    .Select(d => new { Resource = GetResourceInfo(d), Method = d })
                    .Where(d => d.Resource != null)
                    .GroupBy(d => d.Resource, d => d.Method)
                    .Select(g => new
                    {
                        Resource = g.Key,
                        Methods = g.GroupBy(m =>
                            GetMethodName((ReflectedHttpActionDescriptor)m.ActionDescriptor)).Select(m => m.First()).ToList(),
                    })
                    .Select(cd => new MetadataResource
                    {
                        Name = cd.Resource.Name,
                        Documentation = cd.Resource.Description,
                        Properties = cd.Resource.Type == null ? null : _helper.GetTypeParameters(cd.Resource.Type),
                        Methods = cd.Methods
                            .Where(m => GetMethodName((ReflectedHttpActionDescriptor)m.ActionDescriptor) != null)
                            .Select(m => new MetadataMethod
                            {
                                Name = GetMethodName((ReflectedHttpActionDescriptor)m.ActionDescriptor),
                                Documentation = GetMethodDocumentation((ReflectedHttpActionDescriptor)m.ActionDescriptor),
                                Verb = m.HttpMethod.Method,
                                Uri = "/" + m.RelativePath,
                                UriParameters = GetUrlParameters(m),
                                Authorization = GetAuthorization(m.ActionDescriptor),
                                RequestDocumentation = GetRequestDocumentation((ReflectedHttpActionDescriptor)m.ActionDescriptor),
                                RequestParameters = GetRequestParameters((ReflectedHttpActionDescriptor)m.ActionDescriptor),
                                ResponseDocumentation = GetResponseDocumentation((ReflectedHttpActionDescriptor)m.ActionDescriptor),
                                ResponseParameters = GetResponseParameters((ReflectedHttpActionDescriptor)m.ActionDescriptor),
                            }).ToArray(),
                    }).ToArray(),
            };

            return metadata;
        }
        public Metadata Generate()
        {
            var controllers = typeof(ControllerBase).Assembly.GetTypes()
                .Where(t => !t.IsAbstract && typeof(ControllerBase).IsAssignableFrom(t)).ToArray();

            var services = new List<MetadataService>();
            foreach (var controller in controllers)
            {
                var methods = new List<MetadataMethod>();

                // inbound messages
                foreach (var action in controller.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                    .Where(m => m.IsDefined(typeof(ActionAttribute), true)))
                {
                    var actionAttribute = action.GetCustomAttributes(typeof(ActionAttribute), true).Cast<ActionAttribute>().First();
                    methods.Add(new MetadataMethod
                    {
                        Name = actionAttribute.ActionName,
                        Documentation = _wsXmlCommentReader.GetMethodElement(action).ElementContents("summary"),
                        Originator = IsDeviceMethod(action) ? "Device" : "Client",
                        Authorization = GetAuthorization(action),
                        RequestParameters = GetRequestParameters(action),
                        ResponseParameters = GetResponseParameters(action, actionAttribute.ActionName),
                    });
                }

                // outbound messages
                foreach (var action in controller.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
                {
                    var methodElement = _wsXmlCommentReader.GetMethodElement(action);
                    var actionElement = methodElement == null ? null : methodElement.Element("action");
                    if (actionElement == null)
                        continue;

                    methods.Add(new MetadataMethod
                    {
                        Name = "srv: " + actionElement.Contents(),
                        Documentation = methodElement.ElementContents("summary"),
                        Originator = "Server",
                        Authorization = "n/a",
                        ResponseParameters = GetResponseParameters(action, actionElement.Contents()),
                    });
                }

                services.Add(new MetadataService
                {
                    Name = controller.Name.Replace("Controller", ""),
                    Uri = "/" + controller.Name.Replace("Controller", "").ToLower(),
                    Documentation = _wsXmlCommentReader.GetTypeElement(controller).ElementContents("summary"),
                    Methods = methods.OrderBy(m => m.Name).ToArray(),
                });
            }
            var metadata = new Metadata { Services = services.ToArray() };
            return metadata;
        }