Example #1
0
        /// <summary>
        /// Writes an EPM attribute target.
        /// </summary>
        /// <param name="writer">The writer to write to.</param>
        /// <param name="targetSegment">The target segment describing the attribute to write.</param>
        /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param>
        /// <param name="resourceType">The resource type of the entry.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        /// <param name="alreadyDeclaredPrefix">The name of the prefix if it was already declared.</param>
        private static void WriteAttributeEpm(
            XmlWriter writer,
            EpmTargetPathSegment targetSegment,
            EntryPropertiesValueCache epmValueCache,
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata,
            ref string alreadyDeclaredPrefix)
        {
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(targetSegment != null && targetSegment.IsAttribute, "Only attribute target segments are supported by this method.");
            Debug.Assert(targetSegment.HasContent, "Attribute target segments must have content.");

            string textPropertyValue = GetEntryPropertyValueAsText(targetSegment, epmValueCache, resourceType, metadata);

            Debug.Assert(textPropertyValue != null, "Text value of a property mapped to attribute must not be null, the GetEntryPropertyValueAsText should take care of that.");

            // If the prefix is null, the WCF DS will still write it as the default namespace, so we need it to be an empty string.
            string attributePrefix = targetSegment.SegmentNamespacePrefix ?? string.Empty;

            writer.WriteAttributeString(attributePrefix, targetSegment.AttributeName, targetSegment.SegmentNamespaceUri, textPropertyValue);

            // Write out the declaration explicitely only if the prefix is not empty (just like the WCF DS does)
            if (attributePrefix.Length > 0)
            {
                WriteNamespaceDeclaration(writer, targetSegment, ref alreadyDeclaredPrefix);
            }
        }
Example #2
0
        public void AskJustOncesForTypeTest()
        {
            var typesToTest = new Func <DSPMetadata, ResourceType>[] {
                (metadata) =>
                {
                    var t = metadata.AddEntityType("EntityType", null, null, false);
                    metadata.AddKeyProperty(t, "ID", typeof(int));
                    return(t);
                },
                (metadata) => metadata.AddComplexType("ComplexType", null, null, false)
            };

            AstoriaTestNS.TestUtil.RunCombinations(
                typesToTest,
                (typeCreate) =>
            {
                var metadataProvider = new CallCountMetadataProvider("Test", "TestNS");
                var type             = typeCreate(metadataProvider);
                metadataProvider.SetReadOnly();
                var wrapper      = new DataServiceMetadataProviderWrapper(metadataProvider);
                var resourceType = wrapper.TryResolveResourceType(type.FullName);
                Assert.AreSame(type, resourceType, "The returned type is not the one expected.");
                wrapper.TryResolveResourceType(type.FullName);
                wrapper.TryResolveResourceType(type.FullName);
                Assert.AreEqual(1, metadataProvider.TryResolveResourceTypeCallCount, "The underlying metadata provider should be called just once.");
            });
        }
        /// <summary>
        /// Writes out the value of a complex property.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="complexValue">The complex value to write.</param>
        /// <param name="metadataType">The metadata type for the complex value.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <param name="isWritingCollection">True if we are writing a collection instead of an entry.</param>
        /// <param name="version">The protocol version used for writing.</param>
        /// <param name="epmValueCache">Cache of values used in EPM so that we avoid multiple enumerations of properties/items. (can be null)</param>
        /// <param name="epmSourcePathSegment">The EPM source path segment which points to the property we're writing. (can be null)</param>
        internal static void WriteComplexValue(
            XmlWriter writer,
            DataServiceMetadataProviderWrapper metadata,
            ODataComplexValue complexValue,
            ResourceType metadataType,
            bool isOpenPropertyType,
            bool isWritingCollection,
            ODataVersion version,
            EpmValueCache epmValueCache,
            EpmSourcePathSegment epmSourcePathSegment)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");

            string typeName = complexValue.TypeName;

            // resolve the type name to the resource type; if no type name is specified we will use the
            // type inferred from metadata
            ResourceType complexValueType = MetadataUtils.ResolveTypeName(metadata, metadataType, ref typeName, ResourceTypeKind.ComplexType, isOpenPropertyType);

            if (typeName != null)
            {
                WritePropertyTypeAttribute(writer, typeName);
            }

            WriteProperties(
                writer,
                metadata,
                complexValueType,
                EpmValueCache.GetComplexValueProperties(epmValueCache, epmSourcePathSegment, complexValue, true),
                version,
                isWritingCollection,
                epmValueCache,
                epmSourcePathSegment);
        }
Example #4
0
        /// <summary>
        /// Writes the custom mapped EPM properties to an XML writer which is expected to be positioned such to write
        /// a child element of the entry element.
        /// </summary>
        /// <param name="writer">The XmlWriter to write to.</param>
        /// <param name="epmTargetTree">The EPM target tree to use.</param>
        /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param>
        /// <param name="resourceType">The resource type of the entry.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        internal static void WriteEntryEpm(
            XmlWriter writer,
            EpmTargetTree epmTargetTree,
            EntryPropertiesValueCache epmValueCache,
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(epmTargetTree != null, "epmTargetTree != null");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");
            Debug.Assert(resourceType != null, "For any EPM to exist the metadata must be available.");

            // If there are no custom mappings, just return null.
            EpmTargetPathSegment customRootSegment = epmTargetTree.NonSyndicationRoot;

            Debug.Assert(customRootSegment != null, "EPM Target tree must always have non-syndication root.");
            if (customRootSegment.SubSegments.Count == 0)
            {
                return;
            }

            foreach (EpmTargetPathSegment targetSegment in customRootSegment.SubSegments)
            {
                Debug.Assert(!targetSegment.IsAttribute, "Target segments under the custom root must be for elements only.");

                string alreadyDeclaredPrefix = null;
                WriteElementEpm(writer, targetSegment, epmValueCache, resourceType, metadata, ref alreadyDeclaredPrefix);
            }
        }
Example #5
0
        /// <summary>
        /// Validates a type name to ensure that it's not an empty string.
        /// </summary>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="typeName">The type name to validate.</param>
        /// <param name="typeKind">The expected type kind for the given type name.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <returns>The resource type with the given name and kind if the metadata was available, otherwise null.</returns>
        internal static ResourceType ValidateTypeName(DataServiceMetadataProviderWrapper metadata, string typeName, ResourceTypeKind typeKind, bool isOpenPropertyType)
        {
            DebugUtils.CheckNoExternalCallers();

            if (typeName == null)
            {
                // if we have metadata the type name of an entry or a complex value of an open property must not be null
                if (metadata != null && (typeKind == ResourceTypeKind.EntityType || isOpenPropertyType))
                {
                    throw new ODataException(Strings.ODataWriterCore_MissingTypeNameWithMetadata);
                }

                return(null);
            }

            // we do not allow empty type names
            if (typeName.Length == 0)
            {
                throw new ODataException(Strings.ODataWriter_TypeNameMustNotBeEmpty);
            }

            // If we do have metadata, lookup the type and translate it to ResourceType.
            ResourceType resourceType = null;

            if (metadata != null)
            {
                resourceType = typeKind == ResourceTypeKind.MultiValue
                    ? ValidateMultiValueTypeName(metadata, typeName)
                    : ValidateNonMultiValueTypeName(metadata, typeName, typeKind);
            }

            return(resourceType);
        }
Example #6
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="stream">The stream to write to.</param>
        /// <param name="odataWriterSettings">Configuration settings for the writer to create.</param>
        /// <param name="encoding">The encoding to use for writing.</param>
        /// <param name="writingResponse">True if the writer is to write a response payload; false if it's to write a request payload.</param>
        /// <param name="metadataProvider">The metadata provider to use.</param>
        /// <param name="writingFeed">True if the writer is created for writing a feed; false when it is created for writing an entry.</param>
        /// <param name="synchronous">True if the writer is created for synchronous operation; false for asynchronous.</param>
        internal ODataJsonWriter(
            Stream stream,
            ODataWriterSettings odataWriterSettings,
            Encoding encoding,
            bool writingResponse,
            DataServiceMetadataProviderWrapper metadataProvider,
            bool writingFeed,
            bool synchronous)
            : base(
                odataWriterSettings.Version,
                odataWriterSettings.BaseUri,
                writingResponse,
                metadataProvider,
                writingFeed,
                synchronous)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(stream != null, "stream != null");
            Debug.Assert(odataWriterSettings != null, "odataWriterSettings != null");

            this.outputStream = new AsyncBufferedStream(stream);
            this.textWriter   = new StreamWriter(this.outputStream, encoding);

            this.jsonWriter = new JsonWriter(this.textWriter, odataWriterSettings.Indent);
        }
        /// <summary>
        /// Reads a property value starting on a complex value.
        /// </summary>
        /// <param name="complexValue">The complex value to start with.</param>
        /// <param name="complexPropertySegment">The EPM source path segment which points to the <paramref name="complexValue"/>.</param>
        /// <param name="epmValueCache">The EPM value cache to use.</param>
        /// <param name="sourceSegmentIndex">The index in the property value path to start with.</param>
        /// <param name="resourceType">The resource type of the complex value.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        /// <param name="nullOnParentProperty">true if the value of the property is null because one of its parent properties was null, in this case
        /// the return value of the method is always null. false if the value of the property is the actual property value which may or may not be null.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        private object ReadComplexPropertyValue(
            ODataComplexValue complexValue,
            EpmSourcePathSegment complexPropertySegment,
            EpmValueCache epmValueCache,
            int sourceSegmentIndex,
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata,
            out bool nullOnParentProperty)
        {
            Debug.Assert(this.propertyValuePath != null, "The propertyValuePath should have been initialized by now.");
            Debug.Assert(this.propertyValuePath.Length > sourceSegmentIndex, "The propertyValuePath must be at least as long as the source segment index.");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");
            Debug.Assert(sourceSegmentIndex >= 0, "sourceSegmentIndex >= 0");
            Debug.Assert(resourceType != null, "resourceType != null");

            if (complexValue == null)
            {
                nullOnParentProperty = true;
                return(null);
            }

            return(this.ReadPropertyValue(
                       EpmValueCache.GetComplexValueProperties(epmValueCache, complexPropertySegment, complexValue, false),
                       sourceSegmentIndex,
                       resourceType,
                       metadata,
                       epmValueCache,
                       out nullOnParentProperty));
        }
Example #8
0
        private static void CreateCallCounterService(out CallCountMetadataProvider metadataProvider, out DSPServiceDefinition service)
        {
            metadataProvider = new CallCountMetadataProvider("DefaultContainer", "Default");

            var entityType = metadataProvider.AddEntityType("EntityType", null, null, false /*isAbstract*/);

            metadataProvider.AddKeyProperty(entityType, "ID", typeof(int));
            metadataProvider.AddPrimitiveProperty(entityType, "LastUpdatedAuthor", typeof(string), true /*eTag*/);

            var derivedType = metadataProvider.AddEntityType("DerivedType", null, entityType, false /*isAbstract*/);

            metadataProvider.AddPrimitiveProperty(derivedType, "LastModifiedAuthor", typeof(string), true /*eTag*/);

            metadataProvider.AddResourceSet("Customers", entityType);

            var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);

            DSPContext dataContext = new DSPContext();

            service = new DSPServiceDefinition()
            {
                Metadata             = metadataProvider,
                CreateDataSource     = (m) => dataContext,
                ForceVerboseErrors   = true,
                MediaResourceStorage = new DSPMediaResourceStorage(),
                SupportNamedStream   = true,
                Writable             = true,
                DataServiceBehavior  = new OpenWebDataServiceDefinition.OpenWebDataServiceBehavior()
                {
                    IncludeRelationshipLinksInResponse = true
                },
            };
        }
        /// <summary>
        /// Creates an <see cref="ODataCollectionWriter"/> for the specified message and its stream.
        /// </summary>
        /// <param name="format">The serialization format to create the writer for.</param>
        /// <param name="encoding">The encoding to create the writer with.</param>
        /// <param name="stream">The response stream to write to.</param>
        /// <param name="settings">Writer settings to use.</param>
        /// <param name="metadataProvider">The metadata provider to use.</param>
        /// <param name="synchronous">True if the writer is created for synchronous operation; false for asynchronous.</param>
        /// <returns>The newly created <see cref="ODataCollectionWriter"/> instance.</returns>
        /// <remarks>This is used to create the collection writer once we've obtained the stream from the response.</remarks>
        private static ODataCollectionWriter CreateCollectionWriter(
            ODataFormat format,
            Encoding encoding,
            Stream stream,
            ODataWriterSettings settings,
            DataServiceMetadataProviderWrapper metadataProvider,
            bool synchronous)
        {
            if (settings.BaseUri != null && !settings.BaseUri.IsAbsoluteUri)
            {
                throw new ODataException(Strings.ODataWriter_BaseUriMustBeNullOrAbsolute(UriUtils.UriToString(settings.BaseUri)));
            }

            switch (format)
            {
            case ODataFormat.Json:
                return(new ODataJsonCollectionWriter(stream, settings, encoding, metadataProvider, synchronous));

            case ODataFormat.Atom:
                return(new ODataAtomCollectionWriter(stream, settings, encoding, metadataProvider, synchronous));

            case ODataFormat.Default:
                Debug.Assert(false, "Should never get here as content-type negotiation should not return Default format for collection.");
                throw new ODataException(Strings.ODataCollectionWriter_CannotCreateCollectionWriterForFormat(format.ToString()));

            default:
                throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ODataCollectionWriter_CreateCollectionWriter_UnreachableCodePath));
            }
        }
Example #10
0
        /// <summary>
        /// Given a target segment the method returns the text value of the property mapped to that segment to be used in EPM.
        /// </summary>
        /// <param name="targetSegment">The target segment to read the value for.</param>
        /// <param name="epmValueCache">The entry EPM value cache to use.</param>
        /// <param name="resourceType">The resource type of the entry being processed.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        /// <returns>The test representation of the value, or the method throws if the text representation was not possible to obtain.</returns>
        private static string GetEntryPropertyValueAsText(
            EpmTargetPathSegment targetSegment,
            EntryPropertiesValueCache epmValueCache,
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata)
        {
            Debug.Assert(targetSegment != null, "targetSegment != null");
            Debug.Assert(targetSegment.HasContent, "The target segment to read property for must have content.");
            Debug.Assert(targetSegment.EpmInfo != null, "The EPM info must be available on the target segment to read its property.");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");
            Debug.Assert(resourceType != null, "resourceType != null");

            bool   nullOnParentProperty;
            object propertyValue = targetSegment.EpmInfo.ReadEntryPropertyValue(epmValueCache, resourceType, metadata, out nullOnParentProperty);

            if (propertyValue == null)
            {
                // TODO: In V3 when we use new format for null values using the m:null attribute we need to check here
                // if we're mapping into an attribute, in which case we should fail (can't write null to attribute in V3)
                // or if we're writing into element return true null, to use the m:null attribute.
                // In V2 nulls are written out as empty string always (and they're written into content as well)
                return(string.Empty);
            }
            else
            {
                return(EpmWriterUtils.GetPropertyValueAsText(propertyValue));
            }
        }
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="version">The version of the OData protocol to use.</param>
 /// <param name="metadataProvider">The metadata provider to use.</param>
 /// <param name="synchronous">True if the writer is created for synchronous operation; false for asynchronous.</param>
 protected ODataCollectionWriterCore(ODataVersion version, DataServiceMetadataProviderWrapper metadataProvider, bool synchronous)
 {
     DebugUtils.CheckNoExternalCallers();
     this.version          = version;
     this.metadataProvider = metadataProvider;
     this.synchronous      = synchronous;
     this.scopes.Push(new Scope(CollectionWriterState.Start, null));
 }
Example #12
0
        /// <summary>
        /// Writes an EPM element target.
        /// </summary>
        /// <param name="writer">The writer to write to.</param>
        /// <param name="targetSegment">The target segment describing the element to write.</param>
        /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param>
        /// <param name="resourceType">The resource type of the entry.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        /// <param name="alreadyDeclaredPrefix">The name of the prefix if it was already declared.</param>
        private static void WriteElementEpm(
            XmlWriter writer,
            EpmTargetPathSegment targetSegment,
            EntryPropertiesValueCache epmValueCache,
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata,
            ref string alreadyDeclaredPrefix)
        {
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(targetSegment != null && !targetSegment.IsAttribute, "Only element target segments are supported by this method.");

            // If the prefix is null, the WCF DS will still write it as the default namespace, so we need it to be an empty string.
            string elementPrefix = targetSegment.SegmentNamespacePrefix ?? string.Empty;

            writer.WriteStartElement(elementPrefix, targetSegment.SegmentName, targetSegment.SegmentNamespaceUri);

            // Write out the declaration explicitly only if the prefix is not empty (just like the WCF DS does)
            if (elementPrefix.Length > 0)
            {
                WriteNamespaceDeclaration(writer, targetSegment, ref alreadyDeclaredPrefix);
            }

            // Serialize the sub segment attributes first
            foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments)
            {
                if (subSegment.IsAttribute)
                {
                    WriteAttributeEpm(writer, subSegment, epmValueCache, resourceType, metadata, ref alreadyDeclaredPrefix);
                }
            }

            if (targetSegment.HasContent)
            {
                Debug.Assert(!targetSegment.SubSegments.Any(subSegment => !subSegment.IsAttribute), "If the segment has a content, it must not have any element children.");

                string textPropertyValue = GetEntryPropertyValueAsText(targetSegment, epmValueCache, resourceType, metadata);

                // TODO: In V3 we should check for textPropertyValue == null and write out the m:null in that case.
                Debug.Assert(textPropertyValue != null, "Null property value should not get here, the GetEntryPropertyValueAsText should take care of that for now.");

                writer.WriteString(textPropertyValue);
            }
            else
            {
                // Serialize the sub segment elements now
                foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments)
                {
                    if (!subSegment.IsAttribute)
                    {
                        WriteElementEpm(writer, subSegment, epmValueCache, resourceType, metadata, ref alreadyDeclaredPrefix);
                    }
                }
            }

            // Close the element
            writer.WriteEndElement();
        }
Example #13
0
        public void AskJustOncesForServiceOperationTest()
        {
            var metadataProvider = new CallCountMetadataProvider("Test", "TestNS");
            var serviceOperation = metadataProvider.AddServiceOperation("ServiceOperation", ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(string)), null, "GET", new ServiceOperationParameter[0]);

            metadataProvider.SetReadOnly();
            var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);

            wrapper.TryResolveServiceOperation(serviceOperation.Name);
            wrapper.TryResolveServiceOperation(serviceOperation.Name);
            wrapper.TryResolveServiceOperation(serviceOperation.Name);
            Assert.AreEqual(1, metadataProvider.TryResolveServiceOperationCallCount, "The underlying metadata provider should be called just once.");
        }
Example #14
0
        /// <summary>
        /// Writes a name/value pair for a property.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="property">The property to write out.</param>
        /// <param name="owningType">The type owning the property (or null if no metadata is available).</param>
        /// <param name="version">The protocol version used for writing.</param>
        private static void WriteProperty(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataProperty property,
            ResourceType owningType,
            ODataVersion version)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");

            ValidationUtils.ValidateProperty(property);
            ResourceProperty resourceProperty   = ValidationUtils.ValidatePropertyDefined(property.Name, owningType);
            bool             isOpenPropertyType = owningType != null && owningType.IsOpenType && resourceProperty == null;

            jsonWriter.WriteName(property.Name);
            object value = property.Value;

            if (value == null)
            {
                // verify that MultiValue properties are not null
                if (resourceProperty != null && resourceProperty.Kind == ResourcePropertyKind.MultiValue)
                {
                    throw new ODataException(Strings.ODataWriter_MultiValuePropertiesMustNotHaveNullValue(resourceProperty.Name));
                }

                jsonWriter.WriteValue(null);
            }
            else
            {
                ResourceType      resourcePropertyType = resourceProperty == null ? null : resourceProperty.ResourceType;
                ODataComplexValue complexValue         = value as ODataComplexValue;
                if (complexValue != null)
                {
                    WriteComplexValue(jsonWriter, metadata, complexValue, resourcePropertyType, isOpenPropertyType, version);
                }
                else
                {
                    ODataMultiValue multiValue = value as ODataMultiValue;
                    if (multiValue != null)
                    {
                        ODataVersionChecker.CheckMultiValueProperties(version, property.Name);
                        WriteMultiValue(jsonWriter, metadata, multiValue, resourcePropertyType, isOpenPropertyType, version);
                    }
                    else
                    {
                        WritePrimitiveValue(jsonWriter, value, resourcePropertyType);
                    }
                }
            }
        }
Example #15
0
        /// <summary>
        /// Create a func which created an <see cref="ODataCollectionWriter"/> for a given request message and stream.
        /// </summary>
        /// <param name="message">The message to create the writer for.</param>
        /// <param name="settings">Configuration settings for the writer to create.</param>
        /// <param name="format">The OData format used for serialization of the payload.</param>
        /// <param name="encoding">The encoding used for serialization of the payload.</param>
        /// <param name="metadataProvider">The metadata provider to use.</param>
        /// <param name="synchronous">True if the writer is created for synchronous operation; false for asynchronous.</param>
        /// <returns>A task returning an OData collection writer to write the payload of the request/response.</returns>
        internal static Func <Stream, ODataCollectionWriter> Create(
            ODataMessage message,
            ODataWriterSettings settings,
            ODataFormat format,
            Encoding encoding,
            DataServiceMetadataProviderWrapper metadataProvider,
            bool synchronous)
        {
            DebugUtils.CheckNoExternalCallers();
            ExceptionUtils.CheckArgumentNotNull(message, "message");
            ExceptionUtils.CheckArgumentNotNull(settings, "settings");

            return((stream) => CreateCollectionWriter(format, encoding, stream, settings, metadataProvider, synchronous));
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="stream">The stream to write to.</param>
        /// <param name="writerSettings">Configuration settings for the writer to create.</param>
        /// <param name="encoding">The encoding to use for writing.</param>
        /// <param name="metadataProvider">The metadata provider to use.</param>
        /// <param name="synchronous">True if the writer is created for synchronous operation; false for asynchronous.</param>
        internal ODataAtomCollectionWriter(
            Stream stream,
            ODataWriterSettings writerSettings,
            Encoding encoding,
            DataServiceMetadataProviderWrapper metadataProvider,
            bool synchronous)
            : base(writerSettings.Version, metadataProvider, synchronous)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(stream != null, "stream != null");
            Debug.Assert(writerSettings != null, "writerSettings != null");

            this.outputStream = new AsyncBufferedStream(stream);
            this.writer       = ODataAtomWriterUtils.CreateXmlWriter(this.outputStream, writerSettings, encoding);
        }
Example #17
0
        public void AllowRedefiningConcurrencyTokenOnDerivedType()
        {
            var metadataProvider = new DSPMetadata("DefaultContainer", "Default");

            var entityType = metadataProvider.AddEntityType("EntityType", null, null, false /*isAbstract*/);

            metadataProvider.AddKeyProperty(entityType, "ID", typeof(int));
            metadataProvider.AddPrimitiveProperty(entityType, "LastUpdatedAuthor", typeof(string), true /*eTag*/);

            var derivedType = metadataProvider.AddEntityType("DerivedType", null, entityType, false /*isAbstract*/);

            metadataProvider.AddPrimitiveProperty(derivedType, "LastModifiedAuthor", typeof(string), true /*eTag*/);

            metadataProvider.AddResourceSet("Customers", entityType);

            var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);

            DSPResource baseTypeInstance = new DSPResource(entityType);

            baseTypeInstance.SetValue("ID", 1);
            baseTypeInstance.SetValue("LastUpdatedAuthor", "Phani");

            DSPResource derivedTypeInstance = new DSPResource(derivedType);

            derivedTypeInstance.SetValue("ID", 1);
            derivedTypeInstance.SetValue("LastModifiedAuthor", "Raj");

            DSPContext dataContext = new DSPContext();
            var        entities    = dataContext.GetResourceSetEntities("Customers");

            entities.AddRange(new object[] { baseTypeInstance, derivedTypeInstance });

            var service = new DSPUnitTestServiceDefinition(metadataProvider, DSPDataProviderKind.Reflection, dataContext);

            using (TestWebRequest request = service.CreateForInProcess())
            {
                try
                {
                    request.StartService();
                    request.RequestUriString = "/$metadata";
                    request.SendRequestAndCheckResponse();
                }
                finally
                {
                    request.StopService();
                }
            }
        }
Example #18
0
        /// <summary>
        /// Resolve a type name against the provided metadata. If no type name is given we either throw (if a type name on the value is required, e.g., on entries)
        /// or infer the type from metadata (if available).
        /// </summary>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="typeFromMetadata">The type inferred from metadata or null if no metadata is available.</param>
        /// <param name="typeName">The type name to be resolved.</param>
        /// <param name="typeKind">The expected type kind of the resolved type.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <returns>A resource type for the <paramref name="typeName"/> or null if no metadata is available.</returns>
        internal static ResourceType ResolveTypeName(DataServiceMetadataProviderWrapper metadata, ResourceType typeFromMetadata, ref string typeName, ResourceTypeKind typeKind, bool isOpenPropertyType)
        {
            DebugUtils.CheckNoExternalCallers();

            ResourceType typeFromValue = ValidationUtils.ValidateTypeName(metadata, typeName, typeKind, isOpenPropertyType);

            typeFromValue = ValidationUtils.ValidateMetadataType(typeFromMetadata, typeFromValue, typeKind);

            // derive the type name from the metadata if available
            if (typeName == null && typeFromValue != null)
            {
                typeName = typeFromValue.FullName;
            }

            return(typeFromValue);
        }
Example #19
0
        public void AskJustOncesForResourceSetTest()
        {
            var metadataProvider = new CallCountMetadataProvider("Test", "TestNS");
            var type             = metadataProvider.AddEntityType("Entity", null, null, false);

            metadataProvider.AddKeyProperty(type, "ID", typeof(int));
            var resourceSet = metadataProvider.AddResourceSet("Entities", type);

            metadataProvider.SetReadOnly();
            var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);

            wrapper.TryResolveResourceSet(resourceSet.Name);
            wrapper.TryResolveResourceSet(resourceSet.Name);
            wrapper.TryResolveResourceSet(resourceSet.Name);
            Assert.AreEqual(1, metadataProvider.TryResolveResourceSetCallCount, "The underlying metadata provider should be called just once.");
        }
Example #20
0
        public void ResourceSetNamesMustBeUniqueTest()
        {
            var metadataProvider = new ResourceSetsOverrideMetadataProvider("Test", "TestNS");

            metadataProvider.ResourceSetValues = new List <ResourceSet>();
            var type = metadataProvider.AddEntityType("EntityType", null, null, false);

            metadataProvider.ResourceSetValues.Add(new ResourceSet("Entities", type));
            metadataProvider.ResourceSetValues.Add(new ResourceSet("Entities", type));
            var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);

            ExceptionUtils.ExpectedException <DataServiceException>(
                () => wrapper.ResourceSets.Cast <object>().Count(),
                "The resource set 'Entities' returned by the provider is not read-only. Please make sure that all the resource sets are set to read-only.",
                "Two resource sets with the same name should fail in the wrapper.");
        }
Example #21
0
        /// <summary>
        /// Given a target segment the method returns the text value of the property mapped to that segment to be used in EPM.
        /// </summary>
        /// <param name="targetSegment">The target segment to read the value for.</param>
        /// <param name="epmValueCache">The entry EPM value cache to use.</param>
        /// <param name="resourceType">The resource type of the entry being processed.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        /// <returns>The test representation of the value, or the method throws if the text representation was not possible to obtain.</returns>
        private static string GetEntryPropertyValueAsText(
            EpmTargetPathSegment targetSegment,
            EntryPropertiesValueCache epmValueCache,
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata)
        {
            Debug.Assert(targetSegment != null, "targetSegment != null");
            Debug.Assert(targetSegment.HasContent, "The target segment to read property for must have content.");
            Debug.Assert(targetSegment.EpmInfo != null, "The EPM info must be available on the target segment to read its property.");
            Debug.Assert(epmValueCache != null, "epmValueCache != null");
            Debug.Assert(resourceType != null, "resourceType != null");

            bool   nullOnParentProperty;
            object propertyValue = targetSegment.EpmInfo.ReadEntryPropertyValue(epmValueCache, resourceType, metadata, out nullOnParentProperty);

            return(EpmWriterUtils.GetPropertyValueAsText(propertyValue));
        }
Example #22
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="version">The version of the OData protocol to use.</param>
        /// <param name="baseUri">The Base URI to use for all the URIs being written.</param>
        /// <param name="writingResponse">True if the writer is to write a response payload; false if it's to write a request payload.</param>
        /// <param name="metadataProvider">The metadata provider to use.</param>
        /// <param name="writingFeed">True if the writer is created for writing a feed; false when it is created for writing an entry.</param>
        /// <param name="synchronous">True if the writer is created for synchronous operation; false for asynchronous.</param>
        protected ODataWriterCore(
            ODataVersion version,
            Uri baseUri,
            bool writingResponse,
            DataServiceMetadataProviderWrapper metadataProvider,
            bool writingFeed,
            bool synchronous)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(baseUri == null || baseUri.IsAbsoluteUri, "baseUri must be either null or absolute");

            this.version          = version;
            this.baseUri          = baseUri;
            this.writingResponse  = writingResponse;
            this.metadataProvider = metadataProvider;
            this.writingFeed      = writingFeed;
            this.synchronous      = synchronous;
            this.scopes.Push(Scope.Create(WriterState.Start, null));
        }
Example #23
0
        /// <summary>
        /// Validates that <paramref name="typeName"/> is a valid type name of the specified kind (<paramref name="typeKind"/>).
        /// </summary>
        /// <param name="metadata">The metadata against which to validate the type name.</param>
        /// <param name="typeName">The type name to validate.</param>
        /// <param name="typeKind">The expected <see cref="ResourceTypeKind"/> of the type.</param>
        /// <returns>A <see cref="ResourceType"/> for the <paramref name="typeName"/>.</returns>
        internal static ResourceType ValidateNonMultiValueTypeName(DataServiceMetadataProviderWrapper metadata, string typeName, ResourceTypeKind typeKind)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(metadata != null, "metadata != null");

            ResourceType resourceType = metadata.TryResolveResourceType(typeName);

            if (resourceType == null)
            {
                throw new ODataException(Strings.ODataWriterCore_UnrecognizedTypeName(typeName, typeKind));
            }

            if (resourceType.ResourceTypeKind != typeKind)
            {
                throw new ODataException(Strings.ODataWriterCore_IncorrectTypeKind(typeName, typeKind.ToString(), resourceType.ResourceTypeKind.ToString()));
            }

            return(resourceType);
        }
Example #24
0
        /// <summary>
        /// Writes a service document in JSON format.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="defaultWorkspace">The default workspace to write in the service document.</param>
        internal static void WriteServiceDocument(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataWorkspace defaultWorkspace)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(defaultWorkspace != null, "defaultWorkspace != null");

            IEnumerable <ODataResourceCollectionInfo> collections =
                ValidationUtils.ValidateWorkspace(metadata == null ? null : metadata.ResourceSets, defaultWorkspace);

            Debug.Assert(collections != null, "collections != null");

            WriteDataWrapper(
                jsonWriter,
                true,
                () =>
            {
                // "{"
                jsonWriter.StartObjectScope();

                // "EntitySets":
                jsonWriter.WriteName(JsonConstants.ODataServiceDocumentEntitySetsName);

                // "["
                jsonWriter.StartArrayScope();

                foreach (ODataResourceCollectionInfo collectionInfo in collections)
                {
                    ValidationUtils.ValidateResourceCollectionInfo(collectionInfo);

                    // <collection name>
                    jsonWriter.WriteValue(collectionInfo.Name);
                }

                // "]"
                jsonWriter.EndArrayScope();

                // "}"
                jsonWriter.EndObjectScope();
            });
        }
Example #25
0
        public void ServiceOperationsMustBeReadOnlyTest()
        {
            var serviceOperationEntryPoints = new Action <DataServiceMetadataProviderWrapper, string>[] {
                (wrapper, name) => wrapper.TryResolveServiceOperation(name),
            };

            AstoriaTestNS.TestUtil.RunCombinations(
                serviceOperationEntryPoints,
                (serviceOperationEntryPoint) =>
            {
                var metadataProvider = new DSPMetadata("Test", "TestNS");
                var serviceOperation = metadataProvider.AddServiceOperation("ServiceOperation", ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(string)), null, "GET", new ServiceOperationParameter[0]);
                var wrapper          = new DataServiceMetadataProviderWrapper(metadataProvider);
                ExceptionUtils.ExpectedException <DataServiceException>(
                    () => serviceOperationEntryPoint(wrapper, serviceOperation.Name),
                    "The service operation '" + serviceOperation.Name + "' returned by the provider is not read-only. Please make sure that all the service operations are set to read-only.",
                    "Accessing writable service operation should fail.");
            });
        }
Example #26
0
        /// <summary>
        /// Writes out the value of a complex property.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="complexValue">The complex value to write.</param>
        /// <param name="resourcePropertyType">The metadata type for the complex value.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <param name="version">The protocol version used for writing.</param>
        internal static void WriteComplexValue(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataComplexValue complexValue,
            ResourceType resourcePropertyType,
            bool isOpenPropertyType,
            ODataVersion version)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");

            // Start the object scope which will represent the entire complex instance
            jsonWriter.StartObjectScope();

            // Write the "__metadata" : { "type": "typename" }
            // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely
            string typeName = complexValue.TypeName;

            // resolve the type name to the resource type; if no type name is specified we will use the
            // type inferred from metadata
            ResourceType complexValueType = MetadataUtils.ResolveTypeName(metadata, resourcePropertyType, ref typeName, ResourceTypeKind.ComplexType, isOpenPropertyType);

            if (typeName != null)
            {
                // Write the __metadata object
                jsonWriter.WriteName(JsonConstants.ODataMetadataName);
                jsonWriter.StartObjectScope();

                // "type": "typename"
                jsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                jsonWriter.WriteValue(typeName);

                // End the __metadata
                jsonWriter.EndObjectScope();
            }

            // Write the properties of the complex value as usual
            WriteProperties(jsonWriter, metadata, complexValueType, complexValue.Properties, version);

            // End the object scope which represents the complex instance
            jsonWriter.EndObjectScope();
        }
Example #27
0
        public void TypesMustBeReadOnlyTest()
        {
            var typesToTest = new Func <DSPMetadata, ResourceType>[] {
                (metadata) => metadata.AddEntityType("EntityType", null, null, false),
                (metadata) => metadata.AddComplexType("ComplexType", null, null, false)
            };

            AstoriaTestNS.TestUtil.RunCombinations(
                typesToTest,
                (typeCreate) =>
            {
                var metadataProvider = new DSPMetadata("Test", "TestNS");
                var type             = typeCreate(metadataProvider);
                var wrapper          = new DataServiceMetadataProviderWrapper(metadataProvider);
                ExceptionUtils.ExpectedException <DataServiceException>(
                    () => wrapper.TryResolveResourceType(type.FullName),
                    "The resource type '" + type.FullName + "' returned by the provider is not read-only. Please make sure that all the types are set to read-only.",
                    "Resolving resource type to writable type should fail.");
            });
        }
Example #28
0
        /// <summary>
        /// Writes property names and value pairs.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="owningType">The <see cref="ResourceType"/> of the entry (or null if not metadata is available).</param>
        /// <param name="properties">The enumeration of properties to write out.</param>
        /// <param name="version">The protocol version used for writing.</param>
        internal static void WriteProperties(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ResourceType owningType,
            IEnumerable <ODataProperty> properties,
            ODataVersion version)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");

            if (properties == null)
            {
                return;
            }

            foreach (ODataProperty property in properties)
            {
                WriteProperty(jsonWriter, metadata, property, owningType, version);
            }
        }
        public void TypesMustBeReadOnlyTest()
        {
            var typesToTest = new Func<DSPMetadata, ResourceType>[] {
                (metadata) => metadata.AddEntityType("EntityType", null, null, false),
                (metadata) => metadata.AddComplexType("ComplexType", null, null, false)
            };

            AstoriaTestNS.TestUtil.RunCombinations(
                typesToTest,
                (typeCreate) =>
                {
                    var metadataProvider = new DSPMetadata("Test", "TestNS");
                    var type = typeCreate(metadataProvider);
                    var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);
                    ExceptionUtils.ExpectedException<DataServiceException>(
                        () => wrapper.TryResolveResourceType(type.FullName),
                        "The resource type '" + type.FullName + "' returned by the provider is not read-only. Please make sure that all the types are set to read-only.",
                        "Resolving resource type to writable type should fail.");
                });
        }
        /// <summary>
        /// Reads a property value starting on an entry.
        /// </summary>
        /// <param name="epmValueCache">The EPM value cache for the entry to read from.</param>
        /// <param name="resourceType">The resource type of the entry.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        /// <param name="nullOnParentProperty">true if the value of the property is null because one of its parent properties was null, in this case
        /// the return value of the method is always null. false if the value of the property is the actual property value which may or may not be null.</param>
        /// <returns>The value of the property (may be null), or null if the property itself was not found due to one of its parent properties being null.</returns>
        internal object ReadEntryPropertyValue(
            EntryPropertiesValueCache epmValueCache,
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata,
            out bool nullOnParentProperty)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(this.propertyValuePath != null, "The propertyValuePath should have been initialized by now.");
            Debug.Assert(this.propertyValuePath.Length > 0, "The propertyValuePath must not be empty for an entry property.");
            Debug.Assert(resourceType != null, "resourceType != null");

            // TODO - verify that we actually need the internal property PropertyValuePath
            // TODO - It might be possible to avoid the "value" type checks below if we do property value validation based on the resource type
            return(this.ReadPropertyValue(
                       epmValueCache.EntryProperties,
                       0,
                       resourceType,
                       metadata,
                       epmValueCache,
                       out nullOnParentProperty));
        }
Example #31
0
        public void SetsMustBeReadOnlyTest()
        {
            var resourceSetEntryPoints = new Action <DataServiceMetadataProviderWrapper, string>[] {
                (wrapper, name) => wrapper.TryResolveResourceSet(name),
                (wrapper, name) => wrapper.ResourceSets.Cast <object>().Count()
            };

            AstoriaTestNS.TestUtil.RunCombinations(
                resourceSetEntryPoints,
                (resourceSetEntryPoint) =>
            {
                var metadataProvider = new DSPMetadata("Test", "TestNS");
                var resourceType     = metadataProvider.AddEntityType("EntityType", null, null, false);
                var resourceSet      = metadataProvider.AddResourceSet("Entities", resourceType);
                resourceType.SetReadOnly();
                var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);
                ExceptionUtils.ExpectedException <DataServiceException>(
                    () => resourceSetEntryPoint(wrapper, resourceSet.Name),
                    "The resource set '" + resourceSet.Name + "' returned by the provider is not read-only. Please make sure that all the resource sets are set to read-only.",
                    "Accessing writable resource set should fail.");
            });
        }
        public void SetsMustBeReadOnlyTest()
        {
            var resourceSetEntryPoints = new Action<DataServiceMetadataProviderWrapper, string>[] {
                (wrapper, name) => wrapper.TryResolveResourceSet(name),
                (wrapper, name) => wrapper.ResourceSets.Cast<object>().Count()
            };

            AstoriaTestNS.TestUtil.RunCombinations(
                resourceSetEntryPoints,
                (resourceSetEntryPoint) =>
                {
                    var metadataProvider = new DSPMetadata("Test", "TestNS");
                    var resourceType = metadataProvider.AddEntityType("EntityType", null, null, false);
                    var resourceSet = metadataProvider.AddResourceSet("Entities", resourceType);
                    resourceType.SetReadOnly();
                    var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);
                    ExceptionUtils.ExpectedException<DataServiceException>(
                        () => resourceSetEntryPoint(wrapper, resourceSet.Name),
                        "The resource set '" + resourceSet.Name + "' returned by the provider is not read-only. Please make sure that all the resource sets are set to read-only.",
                        "Accessing writable resource set should fail.");
                });
        }
        private static void CreateCallCounterService(out CallCountMetadataProvider metadataProvider, out DSPServiceDefinition service)
        {
            metadataProvider = new CallCountMetadataProvider("DefaultContainer", "Default");

            var entityType = metadataProvider.AddEntityType("EntityType", null, null, false /*isAbstract*/);
            metadataProvider.AddKeyProperty(entityType, "ID", typeof(int));
            metadataProvider.AddPrimitiveProperty(entityType, "LastUpdatedAuthor", typeof(string), true /*eTag*/);

            var derivedType = metadataProvider.AddEntityType("DerivedType", null, entityType, false /*isAbstract*/);
            metadataProvider.AddPrimitiveProperty(derivedType, "LastModifiedAuthor", typeof(string), true /*eTag*/);

            metadataProvider.AddResourceSet("Customers", entityType);

            var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);

            DSPContext dataContext = new DSPContext();

            service = new DSPServiceDefinition()
            {
                Metadata = metadataProvider,
                CreateDataSource = (m) => dataContext,
                ForceVerboseErrors = true,
                MediaResourceStorage = new DSPMediaResourceStorage(),
                SupportNamedStream = true,
                Writable = true,
                DataServiceBehavior = new OpenWebDataServiceDefinition.OpenWebDataServiceBehavior() { IncludeRelationshipLinksInResponse = true },
            };
        }
        public void ServiceOperationsMustBeReadOnlyTest()
        {
            var serviceOperationEntryPoints = new Action<DataServiceMetadataProviderWrapper, string>[] {
                (wrapper, name) => wrapper.TryResolveServiceOperation(name),
            };

            AstoriaTestNS.TestUtil.RunCombinations(
                serviceOperationEntryPoints,
                (serviceOperationEntryPoint) =>
                {
                    var metadataProvider = new DSPMetadata("Test", "TestNS");
                    var serviceOperation = metadataProvider.AddServiceOperation("ServiceOperation", ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(string)), null, "GET", new ServiceOperationParameter[0]);
                    var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);
                    ExceptionUtils.ExpectedException<DataServiceException>(
                        () => serviceOperationEntryPoint(wrapper, serviceOperation.Name),
                        "The service operation '" + serviceOperation.Name + "' returned by the provider is not read-only. Please make sure that all the service operations are set to read-only.",
                        "Accessing writable service operation should fail.");
                });
        }
        public void AskJustOncesForTypeTest()
        {
            var typesToTest = new Func<DSPMetadata, ResourceType>[] {
                (metadata) =>
                {
                    var t = metadata.AddEntityType("EntityType", null, null, false);
                    metadata.AddKeyProperty(t, "ID", typeof(int));
                    return t;
                },
                (metadata) => metadata.AddComplexType("ComplexType", null, null, false)
            };

            AstoriaTestNS.TestUtil.RunCombinations(
                typesToTest,
                (typeCreate) =>
                {
                    var metadataProvider = new CallCountMetadataProvider("Test", "TestNS");
                    var type = typeCreate(metadataProvider);
                    metadataProvider.SetReadOnly();
                    var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);
                    var resourceType = wrapper.TryResolveResourceType(type.FullName);
                    Assert.AreSame(type, resourceType, "The returned type is not the one expected.");
                    wrapper.TryResolveResourceType(type.FullName);
                    wrapper.TryResolveResourceType(type.FullName);
                    Assert.AreEqual(1, metadataProvider.TryResolveResourceTypeCallCount, "The underlying metadata provider should be called just once.");
                });
        }
        public void AllowRedefiningConcurrencyTokenOnDerivedType()
        {
            var metadataProvider = new DSPMetadata("DefaultContainer", "Default");

            var entityType = metadataProvider.AddEntityType("EntityType", null, null, false /*isAbstract*/);
            metadataProvider.AddKeyProperty(entityType, "ID", typeof(int));
            metadataProvider.AddPrimitiveProperty(entityType, "LastUpdatedAuthor", typeof(string), true /*eTag*/);

            var derivedType = metadataProvider.AddEntityType("DerivedType", null, entityType, false /*isAbstract*/);
            metadataProvider.AddPrimitiveProperty(derivedType, "LastModifiedAuthor", typeof(string), true /*eTag*/);

            metadataProvider.AddResourceSet("Customers", entityType);

            var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);

            DSPResource baseTypeInstance = new DSPResource(entityType);
            baseTypeInstance.SetValue("ID", 1);
            baseTypeInstance.SetValue("LastUpdatedAuthor", "Phani");

            DSPResource derivedTypeInstance = new DSPResource(derivedType);
            derivedTypeInstance.SetValue("ID", 1);
            derivedTypeInstance.SetValue("LastModifiedAuthor", "Raj");

            DSPContext dataContext = new DSPContext();
            var entities = dataContext.GetResourceSetEntities("Customers");
            entities.AddRange(new object[] { baseTypeInstance, derivedTypeInstance });

            var service = new DSPUnitTestServiceDefinition(metadataProvider, DSPDataProviderKind.Reflection, dataContext);
            using (TestWebRequest request = service.CreateForInProcess())
            {
                try
                {
                    request.StartService();
                    request.RequestUriString = "/$metadata";
                    request.SendRequestAndCheckResponse();
                }
                finally
                {
                    request.StopService();
                }
            }
        }
 public void ResourceSetNamesMustBeUniqueTest()
 {
     var metadataProvider = new ResourceSetsOverrideMetadataProvider("Test", "TestNS");
     metadataProvider.ResourceSetValues = new List<ResourceSet>();
     var type = metadataProvider.AddEntityType("EntityType", null, null, false);
     metadataProvider.ResourceSetValues.Add(new ResourceSet("Entities", type));
     metadataProvider.ResourceSetValues.Add(new ResourceSet("Entities", type));
     var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);
     ExceptionUtils.ExpectedException<DataServiceException>(
         () => wrapper.ResourceSets.Cast<object>().Count(),
         "The resource set 'Entities' returned by the provider is not read-only. Please make sure that all the resource sets are set to read-only.",
         "Two resource sets with the same name should fail in the wrapper.");
 }
 public void AskJustOncesForServiceOperationTest()
 {
     var metadataProvider = new CallCountMetadataProvider("Test", "TestNS");
     var serviceOperation = metadataProvider.AddServiceOperation("ServiceOperation", ServiceOperationResultKind.DirectValue, ResourceType.GetPrimitiveResourceType(typeof(string)), null, "GET", new ServiceOperationParameter[0]);
     metadataProvider.SetReadOnly();
     var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);
     wrapper.TryResolveServiceOperation(serviceOperation.Name);
     wrapper.TryResolveServiceOperation(serviceOperation.Name);
     wrapper.TryResolveServiceOperation(serviceOperation.Name);
     Assert.AreEqual(1, metadataProvider.TryResolveServiceOperationCallCount, "The underlying metadata provider should be called just once.");
 }
 public void AskJustOncesForResourceSetTest()
 {
     var metadataProvider = new CallCountMetadataProvider("Test", "TestNS");
     var type = metadataProvider.AddEntityType("Entity", null, null, false);
     metadataProvider.AddKeyProperty(type, "ID", typeof(int));
     var resourceSet = metadataProvider.AddResourceSet("Entities", type);
     metadataProvider.SetReadOnly();
     var wrapper = new DataServiceMetadataProviderWrapper(metadataProvider);
     wrapper.TryResolveResourceSet(resourceSet.Name);
     wrapper.TryResolveResourceSet(resourceSet.Name);
     wrapper.TryResolveResourceSet(resourceSet.Name);
     Assert.AreEqual(1, metadataProvider.TryResolveResourceSetCallCount, "The underlying metadata provider should be called just once.");
 }