private static string GetTypeNameMarkdown(string typeName, EntityFramework entityFramework)
        {
            string propertyType = typeName;

            if (propertyType.StartsWith(CollectionPrefix) && propertyType.EndsWith(")"))
            {
                propertyType = propertyType.Substring(CollectionPrefix.Length, propertyType.Length - CollectionPrefix.Length - 1);
                return(GetTypeNameMarkdown(propertyType, entityFramework) + " collection");
            }

            IODataNavigable type = entityFramework.DataServices.Schemas.LookupNavigableType(propertyType);

            var simpleType = type as ODataSimpleType;

            if (simpleType != null)
            {
                return(simpleType.Type.ToString());
            }

            return($"[{type.TypeIdentifier}]({type.TypeIdentifier}.md)");
        }
Example #2
0
        public static IODataNavigable NavigateByFunction(this IODataNavigable source, string component, EntityFramework edmx, bool isLastSegment)
        {
            var matches =
                edmx.DataServices.Schemas.SelectMany(s => s.Functions).
                Where(f =>
                      f.IsBound &&
                      (f.Name == component || f.ParameterizedName == component) &&
                      f.ReturnType?.Type != null &&
                      f.Parameters.Any(p => p.Name == "bindingParameter" && p.Type.TypeOnly() == source.TypeIdentifier.TypeOnly())).
                ToList();

            if (matches.Any())
            {
                foreach (var m in matches)
                {
                    m.IsComposable = true;
                }

                var match = matches.First().ReturnType.Type;
                return(edmx.ResourceWithIdentifier <IODataNavigable>(match));
            }

            var otherCaseName =
                edmx.DataServices.Schemas.SelectMany(s => s.Functions).
                Where(f =>
                      f.IsBound &&
                      (f.Name.IEquals(component) || f.ParameterizedName.IEquals(component)) &&
                      f.Parameters.Any(p => p.Name == "bindingParameter" && p.Type.TypeOnly() == source.TypeIdentifier.TypeOnly())).
                Select(f => f.Name.IEquals(component) ? f.Name : f.ParameterizedName).
                FirstOrDefault();

            if (otherCaseName != null)
            {
                throw new ArgumentException($"ERROR: case mismatch between URL segment '{component}' and schema element '{otherCaseName}'");
            }

            return(null);
        }
Example #3
0
        /// <summary>
        /// Resolve an IODataNavigable instance into a type identifier string.
        /// </summary>
        /// <param name="edmx"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string LookupIdentifierForType(this EntityFramework edmx, IODataNavigable type)
        {
            if (type is ODataSimpleType)
            {
                return(((ODataSimpleType)type).Type.ODataResourceName());
            }
            else if (type is ODataCollection)
            {
                return("Collection(" + ((ODataCollection)type).TypeIdentifier + ")");
            }

            foreach (var schema in edmx.DataServices.Schemas)
            {
                if (type is EntityType)
                {
                    foreach (var et in schema.EntityTypes)
                    {
                        if (et == type)
                        {
                            return(schema.Namespace + "." + et.Name);
                        }
                    }
                }
                else if (type is ComplexType)
                {
                    foreach (var ct in schema.ComplexTypes)
                    {
                        if (ct == type)
                        {
                            return(schema.Namespace + "." + ct.Name);
                        }
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Walks the requestPath through the resources / entities defined in the edmx and resolves
        /// the type of request represented by the path
        /// </summary>
        /// <param name="requestPath"></param>
        /// <param name="requestMethod"></param>
        /// <param name="edmx"></param>
        /// <returns></returns>
        private static ODataTargetInfo ParseRequestTargetType(string requestPath, MethodCollection requestMethodCollection, EntityFramework edmx)
        {
            string[] requestParts = requestPath.Substring(1).Split(new char[] { '/' });

            EntityContainer entryPoint = (from s in edmx.DataServices.Schemas
                                          where s.EntityContainers.Count > 0
                                          select s.EntityContainers.FirstOrDefault()).SingleOrDefault();

            if (entryPoint == null)
            {
                throw new InvalidOperationException("Couldn't locate an EntityContainer to begin target resolution");
            }

            IODataNavigable currentObject  = entryPoint;
            IODataNavigable previousObject = null;

            for (int i = 0; i < requestParts.Length; i++)
            {
                string          uriPart    = requestParts[i];
                IODataNavigable nextObject = null;
                if (uriPart == "{var}")
                {
                    try
                    {
                        nextObject = currentObject.NavigateByEntityTypeKey(edmx);
                    }
                    catch (Exception ex)
                    {
                        throw new NotSupportedException("Unable to navigation into EntityType by key: " + currentObject.TypeIdentifier + " (" + ex.Message + ")");
                    }
                }
                else
                {
                    nextObject = currentObject.NavigateByUriComponent(uriPart, edmx);
                }

                if (nextObject == null && i == requestParts.Length - 1)
                {
                    // The last component wasn't known already, so that means we have a new thing.
                    // We assume that if the uriPart doesnt' have a namespace that this is a navigation property that isn't documented.

                    // TODO: We may need to be smarter about this if we allow actions without namespaces. If that's the case, we could look at the request
                    // method to figure out of this appears to be an action (POST?) or a navigationProperty (GET?)

                    return(new ODataTargetInfo
                    {
                        Name = uriPart,
                        Classification = uriPart.HasNamespace() ? ODataTargetClassification.Unknown : ODataTargetClassification.NavigationProperty,
                        QualifiedType = edmx.LookupIdentifierForType(currentObject)
                    });
                }
                else if (nextObject == null)
                {
                    throw new InvalidOperationException(
                              string.Format("Uri path requires navigating into unknown object hierarchy: missing property '{0}' on '{1}'", uriPart, currentObject.TypeIdentifier));
                }
                previousObject = currentObject;
                currentObject  = nextObject;
            }

            var response = new ODataTargetInfo
            {
                Name          = requestParts.Last(),
                QualifiedType = edmx.LookupIdentifierForType(currentObject)
            };

            if (currentObject is EntityType)
            {
                response.Classification = ODataTargetClassification.EntityType;
            }
            else if (currentObject is EntityContainer)
            {
                response.Classification = ODataTargetClassification.EntityContainer;
            }
            else if (currentObject is ODataSimpleType)
            {
                response.Classification = ODataTargetClassification.SimpleType;
            }
            else if (currentObject is ODataCollection)
            {
                if (previousObject != entryPoint)
                {
                    response.Classification = ODataTargetClassification.NavigationProperty;
                    response.QualifiedType  = edmx.LookupIdentifierForType(previousObject);
                }
                else
                {
                    response.Classification = ODataTargetClassification.EntitySet;
                }
            }
            else if (currentObject is ComplexType)
            {
                throw new NotSupportedException(string.Format("Encountered a ComplexType. This is probably a doc bug where type '{0}' should be defined with keyProperty to be an EntityType", currentObject.TypeIdentifier));
            }
            else
            {
                throw new NotSupportedException(string.Format("Unhandled object type: {0}", currentObject.GetType().Name));
            }

            return(response);
        }