Exemplo n.º 1
0
        // Build the projection tree given a select and expand and the entity set.
        // TODO: Bug 467621: replace this with the ODataUriParser functionality
        public static ODataQueryProjectionNode GetODataQueryProjectionNode(string selectQuery, string expandQuery, IEdmEntitySet entitySet)
        {
            IEnumerable <string> selects = (selectQuery ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim());
            IEnumerable <string> expands = (expandQuery ?? String.Empty).Split(new[] { ',', }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim());

            ODataQueryProjectionNode rootProjectionNode = new ODataQueryProjectionNode {
                Name = String.Empty, NodeType = entitySet.ElementType
            };

            foreach (string expand in expands)
            {
                ODataQueryProjectionNode currentProjectionNode = rootProjectionNode;

                IEnumerable <string> expandPath = expand.Split('/');
                foreach (string property in expandPath)
                {
                    ODataQueryProjectionNode nextNode = currentProjectionNode.Expands.SingleOrDefault(node => node.Name == property);
                    if (nextNode == null)
                    {
                        nextNode = new ODataQueryProjectionNode {
                            Name = property, NodeType = (currentProjectionNode.NodeType as IEdmEntityType).Properties().SingleOrDefault(p => p.Name == property).Type.Definition
                        };
                        currentProjectionNode.Expands.Add(nextNode);
                    }

                    currentProjectionNode = nextNode;
                }
            }

            foreach (string select in selects)
            {
                ODataQueryProjectionNode currentProjectionNode = rootProjectionNode;

                IEnumerable <string> selectPath = select.Split('/');
                foreach (string property in selectPath)
                {
                    ODataQueryProjectionNode nextNode = currentProjectionNode.Expands.SingleOrDefault(node => node.Name == property);
                    if (nextNode == null)
                    {
                        nextNode = new ODataQueryProjectionNode {
                            Name = property, NodeType = (currentProjectionNode.NodeType as IEdmEntityType).Properties().SingleOrDefault(p => p.Name == property).Type.Definition
                        };
                        currentProjectionNode.Selects.Add(nextNode);
                    }

                    currentProjectionNode = nextNode;
                }
            }

            return(rootProjectionNode);
        }
        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            if (type == null)
            {
                throw Error.ArgumentNull("type");
            }

            if (writeStream == null)
            {
                throw Error.ArgumentNull("writeStream");
            }

            HttpContentHeaders contentHeaders = content == null ? null : content.Headers;

            return(TaskHelpers.RunSynchronously(() =>
            {
                // Get the format and version to use from the ODataServiceVersion content header or if not available use the
                // values configured for the specialized formatter instance.
                ODataVersion version;
                ODataFormat odataFormat;
                if (contentHeaders == null)
                {
                    version = _defaultODataVersion;
                    odataFormat = ODataFormatterConstants.DefaultODataFormat;
                }
                else
                {
                    version = GetODataVersion(contentHeaders, ODataFormatterConstants.ODataServiceVersion) ?? _defaultODataVersion;
                    odataFormat = GetODataFormat(contentHeaders);
                }

                ODataSerializer serializer = ODataSerializerProvider.GetODataPayloadSerializer(type);
                if (serializer == null)
                {
                    throw Error.InvalidOperation(SRResources.TypeCannotBeSerialized, type.Name, typeof(ODataMediaTypeFormatter).Name);
                }

                if (IsClient)
                {
                    // TODO: Bug 467617: figure out the story for the operation name on the client side and server side.
                    string operationName = (value != null ? value.GetType() : type).Name;

                    // serialize a request
                    IODataRequestMessage requestMessage = new ODataMessageWrapper(writeStream);
                    ODataResponseContext responseContext = new ODataResponseContext(requestMessage, odataFormat, version, new Uri(ODataFormatterConstants.DefaultNamespace), operationName);

                    ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings()
                    {
                        BaseUri = responseContext.BaseAddress,
                        Version = responseContext.ODataVersion,
                        Indent = responseContext.IsIndented,
                        DisableMessageStreamDisposal = true,
                    };

                    writerSettings.SetContentType(responseContext.ODataFormat);
                    using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, writerSettings, Model))
                    {
                        ODataSerializerWriteContext writeContext = new ODataSerializerWriteContext(responseContext);
                        serializer.WriteObject(value, messageWriter, writeContext);
                    }
                }
                else
                {
                    UrlHelper urlHelper = Request.GetUrlHelper();
                    NameValueCollection queryStringValues = Request.RequestUri.ParseQueryString();

                    IEdmEntitySet targetEntitySet = null;
                    ODataUriHelpers.TryGetEntitySetAndEntityType(Request.RequestUri, Model, out targetEntitySet);

                    ODataQueryProjectionNode rootProjectionNode = null;
                    if (targetEntitySet != null)
                    {
                        // TODO: Bug 467621: Move to ODataUriParser once it is done.
                        rootProjectionNode = ODataUriHelpers.GetODataQueryProjectionNode(queryStringValues["$select"], queryStringValues["$expand"], targetEntitySet);
                    }

                    // serialize a response
                    Uri baseAddress = new Uri(Request.RequestUri, Request.GetConfiguration().VirtualPathRoot);

                    // TODO: Bug 467617: figure out the story for the operation name on the client side and server side.
                    // This is clearly a workaround. We are assuming that the operation name is the last segment in the request uri
                    // which works for most cases and fall back to the type name of the object being written.
                    // We should rather use uri parser semantic tree to figure out the operation name from the request url.
                    string operationName = ODataUriHelpers.GetOperationName(Request.RequestUri, baseAddress);
                    operationName = operationName ?? type.Name;

                    IODataResponseMessage responseMessage = new ODataMessageWrapper(writeStream);
                    ODataResponseContext responseContext = new ODataResponseContext(responseMessage, odataFormat, version, baseAddress, operationName);

                    ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings()
                    {
                        BaseUri = responseContext.BaseAddress,
                        Version = responseContext.ODataVersion,
                        Indent = responseContext.IsIndented,
                        DisableMessageStreamDisposal = true,
                    };
                    if (contentHeaders != null && contentHeaders.ContentType != null)
                    {
                        writerSettings.SetContentType(contentHeaders.ContentType.ToString(), Encoding.UTF8.WebName);
                    }

                    using (ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage, writerSettings, ODataDeserializerProvider.EdmModel))
                    {
                        ODataSerializerWriteContext writeContext = new ODataSerializerWriteContext(responseContext)
                        {
                            EntitySet = targetEntitySet,
                            UrlHelper = urlHelper,
                            RootProjectionNode = rootProjectionNode,
                            CurrentProjectionNode = rootProjectionNode
                        };

                        serializer.WriteObject(value, messageWriter, writeContext);
                    }
                }
            }));
        }