private void CreateNewActionOrFunction(EntityFramework edmx, MethodCollection methodCollection, ODataTargetInfo requestTarget) { // Create a new action (not idempotent) / function (idempotent) based on this request method! ActionOrFunctionBase target = null; if (methodCollection.AllMethodsIdempotent) { target = new Validation.OData.Function(); } else { target = new Validation.OData.Action(); } var schemaName = requestTarget.Name.NamespaceOnly(); target.Name = requestTarget.Name.TypeOnly(); target.IsBound = true; target.Parameters.Add(new Parameter { Name = "bindingParameter", Type = requestTarget.QualifiedType, Nullable = false }); foreach (var param in methodCollection.RequestBodyParameters) { target.Parameters.Add( new Parameter { Name = param.Name, Type = param.Type.ODataResourceName(), Nullable = (param.Required.HasValue ? param.Required.Value : false) }); } if (methodCollection.ResponseType != null) { target.ReturnType = new ReturnType { Type = methodCollection.ResponseType.ODataResourceName(), Nullable = false }; } var schema = FindOrCreateSchemaForNamespace(schemaName, edmx, true); if (target is Function) { schema.Functions.Add((Function)target); } else { schema.Actions.Add((Validation.OData.Action)target); } }
/// <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); }
/// <summary> /// Use the properties of methodCollection to augment what we know about this entity type /// </summary> /// <param name="requestTarget"></param> /// <param name="methodCollection"></param> private void AppendToEntityType(EntityFramework edmx, ODataTargetInfo requestTarget, MethodCollection methodCollection) { StringBuilder sb = new StringBuilder(); const string seperator = ", "; sb.AppendWithCondition(methodCollection.GetAllowed, "GET", seperator); sb.AppendWithCondition(methodCollection.PostAllowed, "POST", seperator); sb.AppendWithCondition(methodCollection.PutAllowed, "PUT", seperator); sb.AppendWithCondition(methodCollection.DeleteAllowed, "DELETE", seperator); Console.WriteLine("EntityType '{0}' supports: ({1})", requestTarget.QualifiedType, sb.ToString()); }
private void AppendToNavigationProperty(EntityFramework edmx, ODataTargetInfo navigationProperty, MethodCollection methods) { EntityType parentType = edmx.ResourceWithIdentifier <EntityType>(navigationProperty.QualifiedType); NavigationProperty matchingProperty = parentType.NavigationProperties.FirstOrDefault(np => np.Name == navigationProperty.Name); if (null != matchingProperty) { // TODO: Append information from methods into this navigation property StringBuilder sb = new StringBuilder(); const string seperator = ", "; sb.AppendWithCondition(methods.GetAllowed, "GET", seperator); sb.AppendWithCondition(methods.PostAllowed, "POST", seperator); sb.AppendWithCondition(methods.PutAllowed, "PUT", seperator); sb.AppendWithCondition(methods.DeleteAllowed, "DELETE", seperator); Console.WriteLine("Collection '{0}' supports: ({1})", navigationProperty.QualifiedType + "/" + navigationProperty.Name, sb); } else { Console.WriteLine( "EntityType '{0}' doesn't have a matching navigationProperty '{1}' but a request exists for this. Sounds like a documentation error.", navigationProperty.QualifiedType, navigationProperty.Name); } }