protected override void WorkspaceCallback(Workspace workspace) { Microsoft.OData.Client.ODataProtocolVersion maxProtocolVersion = Microsoft.OData.Client.ODataProtocolVersion.V4; if (workspace.Settings.MaxProtocolVersion.HasValue) { maxProtocolVersion = workspace.Settings.MaxProtocolVersion.Value; } workspace.GenerateCallOrderInterceptors = true; // use custom concurrency provider for workspaces that can if (workspace.DataLayerProviderKind == DataLayerProviderKind.InMemoryLinq) { if (workspace.Settings.UpdatableImplementation == UpdatableImplementation.DataServiceUpdateProvider) { workspace.ServiceModifications.Interfaces.IServiceProvider.Services[typeof(Microsoft.OData.Service.Providers.IDataServiceUpdateProvider)] = "new UpdateProviderWrapper(this.CurrentDataSource)"; } else { workspace.ServiceModifications.Interfaces.IServiceProvider.Services[typeof(Microsoft.OData.Service.IUpdatable)] = "new UpdatableWrapper(this.CurrentDataSource)"; } } else if (workspace.DataLayerProviderKind == DataLayerProviderKind.NonClr) { workspace.Settings.UpdatableImplementation = UpdatableImplementation.DataServiceUpdateProvider; workspace.Settings.UseLazyPropertyLoading = false; // do this NOW instead of later, so that we can refer to these settings (workspace as NonClrWorkspace).DefineClrProperties(); if (AstoriaTestProperties.UseOpenTypes) { OpenTypesUtil.SetupDefaultOpenTypeAttributes(workspace); } } workspace.ServiceContainer.ResourceContainers.Remove("Invoices"); #region set up etags if (workspace.DataLayerProviderKind != DataLayerProviderKind.LinqToSql) { HashSet <ResourceType> typesWithETags = new HashSet <ResourceType>(); foreach (ResourceContainer container in workspace.ServiceContainer.ResourceContainers) { ResourceType baseType = container.BaseType; if (!typesWithETags.Add(baseType)) { continue; } // set up ETags NodeType[] etagTypes = new NodeType[] { Clr.Types.String, Clr.Types.Int16, Clr.Types.Int32, Clr.Types.Int64, Clr.Types.Guid }; List <ResourceProperty> possibleETagProperties = baseType.Properties.OfType <ResourceProperty>() .Where(p => etagTypes.Contains(p.Type) && !p.IsComplexType && !p.IsNavigation && p.PrimaryKey == null && p.Facets.IsDeclaredProperty && !p.Facets.FixedLength && p.ResourceType == baseType && p.Facets.UnderlyingType == UnderlyingType.Same && !p.Facets.IsStoreBlob && (p.Type != Clr.Types.String || (p.Facets.MaxSize.HasValue && p.Facets.MaxSize.Value < 512))) .ToList(); if (possibleETagProperties.Any()) { baseType.Facets.Add(NodeFacet.Attribute(new ConcurrencyAttribute(baseType, possibleETagProperties.Choose(2).Select(p => p.Name).ToArray()))); } } } #endregion #region set up blobs if (Versioning.Server.SupportsLiveFeatures && workspace.DataLayerProviderKind != DataLayerProviderKind.LinqToSql) { var edmWorkspace = workspace as EdmWorkspace; if (edmWorkspace != null) { edmWorkspace.CsdlCallbacks.Add(delegate(XmlDocument doc) { doc.InnerXml = doc.InnerXml.Replace(TestUtil.TestNamespaceManager.LookupNamespace("csdl"), TestUtil.TestNamespaceManager.LookupNamespace("csdl2")); }); edmWorkspace.SsdlCallbacks.Add(delegate(XmlDocument doc) { doc.InnerXml = doc.InnerXml.Replace("http://schemas.microsoft.com/ado/2006/04/edm/ssdl", "http://schemas.microsoft.com/ado/2009/02/edm/ssdl"); }); edmWorkspace.MslCallbacks.Add(delegate(XmlDocument doc) { doc.InnerXml = doc.InnerXml.Replace("urn:schemas-microsoft-com:windows:storage:mapping:CS", "http://schemas.microsoft.com/ado/2008/09/mapping/cs"); }); } foreach (ResourceContainer container in workspace.ServiceContainer.ResourceContainers.Where(rc => !(rc is ServiceOperation))) { if (workspace.DataLayerProviderKind == DataLayerProviderKind.Edm) { // After named-stream redesign, adding streams to EF is non-trivial continue; } if (container.ResourceTypes.Any(rt => rt.Facets.NamedStreams.Any())) { continue; } // because we don't represent streams as properties, having streams appear on anything other than the absolute base type // makes call order prediction very hard if (container.BaseType.BaseTypes.Any()) { continue; } var type = container.BaseType; switch (AstoriaTestProperties.Random.Next(3)) { case 0: type.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(type, "PhotoStream"))); break; case 1: type.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(type, "PhotoStream"))); type.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(type, "ThumbnailStream"))); type.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(type, "HighResolutionStream"))); break; } } } if (workspace.DataLayerProviderKind != DataLayerProviderKind.LinqToSql) { string streamProviderComparerTypeName = typeof(ReferenceEqualityComparer).FullName; if (workspace.DataLayerProviderKind == DataLayerProviderKind.Edm) { streamProviderComparerTypeName = workspace.Name + "EqualityComparer"; List <string> equalityComparerCode = new List <string>() { "public class " + streamProviderComparerTypeName + " : System.Data.Test.Astoria.KeyBasedEqualityComparerBase", "{", " protected override string[] GetKeyPropertyNames(Type entityType)", " {", " entityType = ObjectContext.GetObjectType(entityType);", " var fullTypeName = entityType.FullName;", }; foreach (var type in workspace.ServiceContainer.ResourceTypes) { equalityComparerCode.Add(string.Join(Environment.NewLine, new string[] { " if(fullTypeName == \"" + type.FullName + "\")", " {", " return new string[] { " + string.Join(", ", type.Properties.Where(p => p.PrimaryKey != null).Select(p => '"' + p.Name + '"').ToArray()) + " };", " }", })); } equalityComparerCode.Add(" throw new Exception(\"Unrecognized type\");"); equalityComparerCode.Add(" }"); equalityComparerCode.Add("}"); workspace.GlobalAdditionalCode += string.Join(Environment.NewLine, equalityComparerCode); } #region for inmemory/nonclr, make all int key properties server generated if (workspace.DataLayerProviderKind == DataLayerProviderKind.NonClr || workspace.DataLayerProviderKind == DataLayerProviderKind.InMemoryLinq) { foreach (ResourceType type in workspace.ServiceContainer.ResourceTypes) { foreach (NodeProperty property in type.Key.Properties) { if (property.Type == Clr.Types.Int32) { property.Facets.ServerGenerated = true; } } } } #endregion #region find possible blob types, and set up stream provider List <ResourceType> possibleBlobTypes = new List <ResourceType>(); foreach (ResourceType type in workspace.ServiceContainer.ResourceContainers.Where(rc => !(rc is ServiceOperation)).Select(rc => rc.BaseType)) { // need to find one that has only generated keys, all other propeties nullable, and no nav props if (type.Key.Properties.Any(p => !p.Facets.ServerGenerated)) { continue; } if (type.Properties.OfType <ResourceProperty>().Any(p => p.PrimaryKey == null && !p.IsNavigation && !p.Facets.Nullable)) { continue; } if (type.Properties.OfType <ResourceProperty>().Any(p => p.IsNavigation)) { continue; } possibleBlobTypes.Add(type); } if (possibleBlobTypes.Any()) { List <ResourceType> blobTypes = new List <ResourceType>(); // want one with etags, and one without ResourceType blobType = possibleBlobTypes.Where(rt => rt.Properties.Any(p => p.Facets.ConcurrencyModeFixed)).Choose(); if (blobType != null) { blobType.Facets.Add(NodeFacet.Attribute(new BlobsAttribute(blobType))); blobTypes.Add(blobType); } blobType = possibleBlobTypes.Where(rt => !rt.Properties.Any(p => p.Facets.ConcurrencyModeFixed)).Choose(); if (blobType != null) { blobType.Facets.Add(NodeFacet.Attribute(new BlobsAttribute(blobType))); blobTypes.Add(blobType); } workspace.ServiceModifications.Interfaces.IServiceProvider.Services[typeof(Microsoft.OData.Service.Providers.IDataServiceStreamProvider)] = "new StreamProviderWrapper(new System.Data.Test.Astoria.InMemoryStreamProvider<" + streamProviderComparerTypeName + ">())"; workspace.Settings.StreamProviderImplementation = StreamProviderImplementation.DataServiceStreamProvider; if (Versioning.Server.SupportsLiveFeatures && workspace.DataLayerProviderKind != DataLayerProviderKind.Edm) { workspace.ServiceModifications.Interfaces.IServiceProvider.Services[typeof(Microsoft.OData.Service.Providers.IDataServiceStreamProvider2)] = "new StreamProvider2Wrapper(new System.Data.Test.Astoria.InMemoryStreamProvider<" + streamProviderComparerTypeName + ">())"; workspace.Settings.StreamProviderImplementation = StreamProviderImplementation.DataServiceStreamProvider2; var blobTypesWithoutNamedStreams = blobTypes.Where(t => !t.Facets.NamedStreams.Any()).ToList(); if (blobTypesWithoutNamedStreams.Count != 0) { var blobTypeWithNamedStreams = blobTypesWithoutNamedStreams.Choose(); blobTypeWithNamedStreams.Facets.Add(NodeFacet.Attribute(new NamedStreamResourceAttribute(blobTypeWithNamedStreams, "Thumbnail"))); } } List <string> typeResolverLines = new List <string>(); foreach (ResourceType rt in blobTypes) { // safe because we know the types are disjoint (either do or do not have etags) and that they were the basetypes of their containers IEnumerable <ResourceContainer> containers = workspace.ServiceContainer.ResourceContainers.Where(rc => rc.BaseType == rt); foreach (ResourceContainer rc in containers) { typeResolverLines.Add(" if(entitySetName == \"" + rc.Name + "\")"); typeResolverLines.Add(" return \"" + rt.Namespace + "." + rt.Name + "\";"); } } typeResolverLines.Add(" return null;"); string typeResolverCode = string.Join(Environment.NewLine, typeResolverLines.ToArray()); workspace.RequiredFrameworkSources.Add("InMemoryStreamProvider.cs"); workspace.RequiredFrameworkSources.Add("KeyBasedEqualityComparerBase.cs"); workspace.RequiredFrameworkSources.Add("ReferenceEqualityComparer.cs"); var streamProviderFile = new ConstructedFile("InMemoryStreamProvider.cs"); workspace.ServiceModifications.Files.Add(streamProviderFile); streamProviderFile.AddMethod("ResolveType", new NewMethodInfo() { MethodSignature = "string ResolveType(string entitySetName, DataServiceOperationContext operationContext)", BodyText = typeResolverCode, }); } #endregion } #endregion #region set up service operations List <ServiceOperation> serviceOperations = new List <ServiceOperation>(); foreach (ResourceContainer container in workspace.ServiceContainer.ResourceContainers) { // no MEST yet for service ops!! if (!workspace.ServiceContainer.ResourceContainers.Any(c => c != container && c.BaseType == container.BaseType)) { foreach (RequestVerb verb in new RequestVerb[] { RequestVerb.Get, RequestVerb.Post }) { ServiceOperation serviceOp = Resource.ServiceOperation(verb.ToString() + "_" + container.Name, container, container.BaseType, container.ResourceTypes.ToArray()); serviceOp.Verb = verb; string fullTypeName = container.BaseType.Namespace + "." + container.BaseType.Name; if (workspace.DataLayerProviderKind == DataLayerProviderKind.NonClr && !container.BaseType.Facets.IsClrType) { fullTypeName = typeof(NonClr.RowEntityType).FullName; } serviceOp.ServiceOpCode = string.Join(Environment.NewLine, new string[] { (verb == RequestVerb.Get ? "[WebGet]" : "[WebInvoke(Method = \"POST\")]"), "public IQueryable<" + fullTypeName + "> " + serviceOp.Name + "()", "{", " return GetEntitySet<" + fullTypeName + ">(\"" + container.Name + "\");", "}" }); serviceOp.ServiceOperationResultKind = Microsoft.OData.Service.Providers.ServiceOperationResultKind.QueryWithMultipleResults; serviceOp.ExpectedTypeName = fullTypeName; serviceOperations.Add(serviceOp); } } } workspace.ServiceContainer.AddNodes(serviceOperations); workspace.AddServiceOperationCode(); #endregion }
private static void RunNegotiatedFormatTest(string requestAccept, string requestMaxVersion, Microsoft.OData.Client.ODataProtocolVersion maxProtocolVersion, ODataFormat expectedFormat) { DataServiceHostSimulator host = new DataServiceHostSimulator { RequestHttpMethod = "GET", RequestAccept = requestAccept, RequestMaxVersion = requestMaxVersion, RequestVersion = "4.0", }; DataServiceSimulator service = new DataServiceSimulator { OperationContext = new DataServiceOperationContext(host), Configuration = new DataServiceConfiguration(new DataServiceProviderSimulator()), }; service.Configuration.DataServiceBehavior.MaxProtocolVersion = maxProtocolVersion; service.OperationContext.InitializeAndCacheHeaders(service); service.OperationContext.RequestMessage.InitializeRequestVersionHeaders(VersionUtil.ToVersion(maxProtocolVersion)); var d = new RequestDescription(RequestTargetKind.Primitive, RequestTargetSource.Property, new Uri("http://temp.org/")); d.DetermineWhetherResponseBodyOrETagShouldBeWritten(service.OperationContext.RequestMessage.HttpVerb); d.DetermineWhetherResponseBodyShouldBeWritten(service.OperationContext.RequestMessage.HttpVerb); d.DetermineResponseFormat(service); d.ResponseFormat.Should().NotBeNull(); d.ResponseFormat.Format.Should().BeSameAs(expectedFormat); }
/// <summary> /// Converts the given product enum value to the equivalent test enum value /// </summary> /// <param name="version">The value to convert</param> /// <returns>The converted value</returns> public static DataServiceProtocolVersion ToTestEnum(this DC.ODataProtocolVersion version) { return(ExtensionMethods.ConvertEnum <DC.ODataProtocolVersion, DataServiceProtocolVersion>(version)); }