/// <summary> /// Initializes a new instance of the <see cref="QueryDescription"/> class with the specified /// <see cref="DomainOperationEntry"/> and parameter values. /// </summary> /// <param name="domainOperationEntry">The query operation to be processed</param> /// <param name="parameterValues">Parameter values for the method if it requires any</param> public QueryDescription(DomainOperationEntry domainOperationEntry, object[] parameterValues) : this(domainOperationEntry) { if (parameterValues == null) { throw new ArgumentNullException("parameterValues"); } this._parameterValues = parameterValues; }
/// <summary> /// Initializes a new instance of the InvokeDescription class /// </summary> /// <param name="domainOperationEntry">The invoke operation to be processed</param> /// <param name="parameterValues">The parameter values for the method if it requires any.</param> public InvokeDescription(DomainOperationEntry domainOperationEntry, object[] parameterValues) { if (domainOperationEntry == null) { throw new ArgumentNullException("domainOperationEntry"); } this._domainOperationEntry = domainOperationEntry; this._parameterValues = parameterValues; }
/// <summary> /// Initializes a new instance of the <see cref="QueryDescription"/> class with the specified /// <see cref="DomainOperationEntry"/>. /// </summary> /// <param name="domainOperationEntry">The query operation to be processed</param> public QueryDescription(DomainOperationEntry domainOperationEntry) { if (domainOperationEntry == null) { throw new ArgumentNullException("domainOperationEntry"); } if (domainOperationEntry.Operation != DomainOperation.Query) { throw new ArgumentOutOfRangeException("domainOperationEntry"); } this._domainOperationEntry = domainOperationEntry; }
public async Task InvokeOperation_ServerValidationException() { TestProvider_Scenarios provider = ServerTestHelper.CreateInitializedDomainService <TestProvider_Scenarios>(DomainOperationType.Invoke); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(TestProvider_Scenarios)); DomainOperationEntry throwValidationExceptionMethod = serviceDescription.GetInvokeOperation("ThrowValidationException"); Assert.IsNotNull(throwValidationExceptionMethod); var invokeResult = await provider.InvokeAsync(new InvokeDescription(throwValidationExceptionMethod, Array.Empty <object>()), CancellationToken.None); Assert.IsNull(invokeResult.Result); Assert.IsNotNull(invokeResult.ValidationErrors); Assert.AreEqual(1, invokeResult.ValidationErrors.Count); Assert.AreEqual("Validation error.", invokeResult.ValidationErrors.ElementAt(0).ErrorMessage); }
/// <summary> /// Get the <see cref="WebInvokeAttribute.UriTemplate"/> which corresponds to the default generated /// UriTemplate for "GET" methods for a given query operation. /// </summary> /// <param name="operation">the query operation for which to get the UriTemplate</param> /// <returns>the default UriTemplate for "GET" methods in case no UriTemplate is specified</returns> private static string GetDefaultQueryUriTemplate(DomainOperationEntry operation) { StringBuilder stringBuilder = new StringBuilder(operation.Name); if (operation.Parameters.Count > 0) { stringBuilder.Append("?"); foreach (DomainOperationParameter parameter in operation.Parameters) { stringBuilder.AppendFormat("{0}={{{0}}}&", parameter.Name); } stringBuilder.Remove(stringBuilder.Length - 1, 1); } return(stringBuilder.ToString()); }
/// <summary> /// Determines whether the specified <see cref="DomainOperationEntry"/> can legally /// be generated. Logs warnings or errors as appropriate. /// </summary> /// <param name="domainOperationEntry">The operation to generate.</param> /// <returns><c>false</c> means an error or warning has been logged and it should not be generated.</returns> private bool CanGenerateDomainOperationEntry(DomainOperationEntry domainOperationEntry) { string methodName = (domainOperationEntry.Operation == DomainOperation.Query) ? domainOperationEntry.Name : domainOperationEntry.Name + QuerySuffix; // Check for name conflicts. Log error and exit if collision. if (this._proxyClass.Members.Cast <CodeTypeMember>().Any(c => c.Name == methodName)) { this.ClientProxyGenerator.LogError( string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_NamingCollision_MemberAlreadyExists, this._proxyClass.Name, methodName)); return(false); } // Check each parameter type to see if is enum DomainOperationParameter[] paramInfos = domainOperationEntry.Parameters.ToArray(); for (int i = 0; i < paramInfos.Length; i++) { DomainOperationParameter paramInfo = paramInfos[i]; // If this is an enum type, we need to ensure it is either shared or // can be generated. Failure logs an error. The test for legality also causes // the enum to be generated if required. Type enumType = TypeUtility.GetNonNullableType(paramInfo.ParameterType); if (enumType.IsEnum) { string errorMessage = null; if (!this.ClientProxyGenerator.CanExposeEnumType(enumType, out errorMessage)) { this.ClientProxyGenerator.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Domain_Op_Enum_Error, domainOperationEntry.Name, this._proxyClass.Name, enumType.FullName, errorMessage)); return(false); } else { // Register use of this enum type, which could cause deferred generation this.ClientProxyGenerator.RegisterUseOfEnumType(enumType); } } } return(true); }
/// <summary> /// Determines whether caching is supported for the current request to the specified domain operation entry. /// </summary> /// <param name="context">The context for the request.</param> /// <param name="domainOperationEntry">The requested domain operation entry, if any.</param> /// <returns>True if caching is supported.</returns> private static bool SupportsCaching(HttpContext context, DomainOperationEntry domainOperationEntry) { if (domainOperationEntry != null && context.Request.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase)) { foreach (string queryParameter in QueryOperationInvoker.supportedQueryParameters) { if (context.Request.QueryString[queryParameter] != null) { return(false); } } return(true); } return(false); }
public void InvokeOperation_ServerValidationException() { TestProvider_Scenarios provider = ServerTestHelper.CreateInitializedDomainService <TestProvider_Scenarios>(DomainOperationType.Invoke); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(TestProvider_Scenarios)); DomainOperationEntry throwValidationExceptionMethod = serviceDescription.GetInvokeOperation("ThrowValidationException"); Assert.IsNotNull(throwValidationExceptionMethod); IEnumerable <ValidationResult> validationErrors; object result = provider.Invoke(new InvokeDescription(throwValidationExceptionMethod, new object[0]), out validationErrors); Assert.IsNull(result); Assert.IsNotNull(validationErrors); Assert.AreEqual(1, validationErrors.Count()); Assert.AreEqual("Validation error.", validationErrors.ElementAt(0).ErrorMessage); }
private void GenerateContractMethod(DomainOperationEntry operation) { this.Write("[OpenRiaServices.DomainServices.Client.HasSideEffects("); this.Write(this.ToStringHelper.ToStringWithCulture(DomainContextGenerator.OperationHasSideEffects(operation).ToString().ToLower())); this.Write(")]\r\n"); this.GenerateContractMethodAttributes(operation.Name); this.Write("System.IAsyncResult Begin"); this.Write(this.ToStringHelper.ToStringWithCulture(operation.Name)); this.Write("(\r\n"); foreach (DomainOperationParameter parameter in operation.Parameters) { Type parameterType = CodeGenUtilities.TranslateType(parameter.ParameterType); this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetTypeName(parameterType))); this.Write(" "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); this.Write(",\r\n"); } this.Write("System.AsyncCallback callback, object asyncState);\r\n"); string returnTypeName = CSharpDomainContextGenerator.GetEndOperationReturnType(operation); this.Write("\t\t\r\n"); this.Write(this.ToStringHelper.ToStringWithCulture(returnTypeName)); this.Write(" End"); this.Write(this.ToStringHelper.ToStringWithCulture(operation.Name)); this.Write("(System.IAsyncResult result);\r\n"); }
public async Task DomainService_InvalidOperationType() { TestDomainServices.EF.Northwind nw = new TestDomainServices.EF.Northwind(); DomainServiceContext dsc = new DomainServiceContext(new MockDataService(new MockUser("mathew") { IsAuthenticated = true }), DomainOperationType.Submit); nw.Initialize(dsc); DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(TestDomainServices.EF.Northwind)); DomainOperationEntry entry = dsd.GetQueryMethod(nameof(TestDomainServices.EF.Northwind.GetOrderDetails)); QueryDescription qd = new QueryDescription(entry); await ExceptionHelper.ExpectExceptionAsync <InvalidOperationException>(() => { return(nw.QueryAsync <NorthwindModel.Order_Detail>(qd, CancellationToken.None).AsTask()); }, string.Format(Resource.DomainService_InvalidOperationType, DomainOperationType.Submit, DomainOperationType.Query)); InvokeDescription id = new InvokeDescription(entry, null); await ExceptionHelper.ExpectExceptionAsync <InvalidOperationException>(() => { return(nw.InvokeAsync(id, CancellationToken.None).AsTask()); }, string.Format(Resource.DomainService_InvalidOperationType, DomainOperationType.Submit, DomainOperationType.Invoke)); nw = new TestDomainServices.EF.Northwind(); dsc = new DomainServiceContext(new MockDataService(new MockUser("mathew") { IsAuthenticated = true }), DomainOperationType.Query); nw.Initialize(dsc); ChangeSet cs = new ChangeSet(new ChangeSetEntry[] { new ChangeSetEntry() { Entity = new ServiceContext_CurrentOperation_Entity() { Key = 1 }, Operation = DomainOperation.Insert } }); await ExceptionHelper.ExpectExceptionAsync <InvalidOperationException>(async() => { await nw.SubmitAsync(cs, CancellationToken.None); }, string.Format(Resource.DomainService_InvalidOperationType, DomainOperationType.Query, DomainOperationType.Submit)); }
public async Task ServiceContext_CurrentOperation() { DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(ServiceContext_CurrentOperation_DomainService)); ServiceContext_CurrentOperation_DomainService ds; // Execute a query. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Query); DomainOperationEntry queryOp = dsd.GetQueryMethod("GetEntities"); Assert.IsNotNull(queryOp); QueryDescription desc = new QueryDescription(queryOp); var queryResult = await ds.QueryAsync <ServiceContext_CurrentOperation_Entity>(desc, CancellationToken.None); Assert.AreEqual(queryOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); // Invoke an operation. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Invoke); DomainOperationEntry invokeOp = dsd.GetInvokeOperation("Echo"); Assert.IsNotNull(invokeOp); await ds.InvokeAsync(new InvokeDescription(invokeOp, null), CancellationToken.None); Assert.AreEqual(invokeOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); // Invoke an insert operation. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Submit); DomainOperationEntry insertOp = dsd.GetSubmitMethod(typeof(ServiceContext_CurrentOperation_Entity), DomainOperation.Insert); Assert.IsNotNull(insertOp); await ds.SubmitAsync(new ChangeSet(new ChangeSetEntry[] { new ChangeSetEntry() { Entity = new ServiceContext_CurrentOperation_Entity() { Key = 1 }, Operation = DomainOperation.Insert } }), CancellationToken.None); Assert.AreEqual(insertOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); }
public void ServiceContext_CurrentOperation() { DomainServiceDescription dsd = DomainServiceDescription.GetDescription(typeof(ServiceContext_CurrentOperation_DomainService)); ServiceContext_CurrentOperation_DomainService ds; IEnumerable <ValidationResult> validationErrors; // Execute a query. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Query); DomainOperationEntry queryOp = dsd.GetQueryMethod("GetEntities"); Assert.IsNotNull(queryOp); QueryDescription desc = new QueryDescription(queryOp); int totalCount; ds.Query(desc, out validationErrors, out totalCount); Assert.AreEqual(queryOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); // Invoke an operation. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Invoke); DomainOperationEntry invokeOp = dsd.GetInvokeOperation("Echo"); Assert.IsNotNull(invokeOp); ds.Invoke(new InvokeDescription(invokeOp, null), out validationErrors); Assert.AreEqual(invokeOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); // Invoke an insert operation. ds = new ServiceContext_CurrentOperation_DomainService(DomainOperationType.Submit); DomainOperationEntry insertOp = dsd.GetSubmitMethod(typeof(ServiceContext_CurrentOperation_Entity), DomainOperation.Insert); Assert.IsNotNull(insertOp); ds.Submit(new ChangeSet(new ChangeSetEntry[] { new ChangeSetEntry() { Entity = new ServiceContext_CurrentOperation_Entity() { Key = 1 }, Operation = DomainOperation.Insert } })); Assert.AreEqual(insertOp, ServiceContext_CurrentOperation_DomainService.LastOperation); Assert.IsNull(ds.Context.Operation); }
public static InvokeDescription GetInvokeDescription(OperationContext context, Expression expression) { context.OperationName = Utility.GetNameFromLambda(expression); IEnumerable <object> parameterValues = Utility.GetParametersFromLambda(expression); DomainOperationEntry domainOperationEntry = context.DomainServiceDescription.GetInvokeOperation(context.OperationName); if (domainOperationEntry == null) { throw new InvalidOperationException(string.Format( CultureInfo.CurrentCulture, Resources.NoInvokeOperation, context.OperationName, context.DomainServiceDescription.DomainServiceType)); } return(new InvokeDescription(domainOperationEntry, parameterValues.ToArray())); }
public async Task TestDomainService_QueryDirect_Throws() { MockDomainService_SelectThrows provider = ServerTestHelper.CreateInitializedDomainService <MockDomainService_SelectThrows>(DomainOperationType.Query); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(provider.GetType()); DomainOperationEntry method = serviceDescription.DomainOperationEntries.First(p => p.Name == "GetEntities" && p.Operation == DomainOperation.Query); QueryDescription qd = new QueryDescription(method, Array.Empty <object>()); await ExceptionHelper.ExpectExceptionAsync <Exception>(async() => { try { await provider.QueryAsync <TestEntity>(qd, CancellationToken.None); } catch (TargetInvocationException ex) { throw ex.InnerException; } }, "Test"); }
/// <summary> /// Helper method performs a invoke operation against a given proxy instance. /// </summary> /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param> /// <param name="context">The current context.</param> /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created /// <see cref="DomainServices"/> will be added to.</param> /// <param name="name">The name of the operation to invoke.</param> /// <param name="parameters">The operation parameters.</param> /// <returns>The result of the invoke operation.</returns> /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception> /// <exception cref="ArgumentNullException">if <paramref name="name"/> is null or an empty string.</exception> /// <exception cref="OperationException">if operation errors are thrown during execution of the invoke operation.</exception> public static object Invoke(Type domainService, DomainServiceContext context, IList <DomainService> domainServiceInstances, string name, object[] parameters) { context = new DomainServiceContext(context, DomainOperationType.Invoke); DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(service.GetType()); DomainOperationEntry method = serviceDescription.GetInvokeOperation(name); IEnumerable <ValidationResult> validationErrors; InvokeDescription invokeDescription = new InvokeDescription(method, parameters); object result = service.Invoke(invokeDescription, out validationErrors); if (validationErrors != null && validationErrors.Any()) { IEnumerable <ValidationResultInfo> operationErrors = validationErrors.Select(ve => new ValidationResultInfo(ve.ErrorMessage, ve.MemberNames)); throw new OperationException(Resource.DomainServiceProxy_OperationError, operationErrors); } return(result); }
public void AuthorizationAttribute_Custom_Method_Custom_Attribute_Null_Entity_Throws() { IPrincipal user = this.CreateIPrincipal("user1"); // Instantiate a new DomainService to use for a custom method via a Submit using (AuthorizationTestDomainService testDomainService = new AuthorizationTestDomainService()) { // Note: Submit context enforces null entity test testDomainService.Initialize(new DomainServiceContext(new MockDataService(user), DomainOperationType.Submit)); DomainServiceDescription description = DomainServiceDescription.GetDescription(typeof(AuthorizationTestDomainService)); DomainOperationEntry entry = description.DomainOperationEntries.SingleOrDefault(p => p.Name == "CustomUpdate"); Assert.IsNotNull(entry, "Did not find CustomUpdate entry"); // The null entity here should raise ArgNull because the context is Submit AuthorizationTestEntity entity = null; ExceptionHelper.ExpectArgumentNullExceptionStandard(() => testDomainService.IsAuthorized(entry, entity), "entity"); } }
/// <summary> /// Builds the default URI temaplate to be used for side-effecting (POST) operations. /// </summary> /// <param name="operation">Domain operation.</param> /// <returns>string representing the default URI temaplate.</returns> private static string BuildDefaultUriTemplate(DomainOperationEntry operation) { StringBuilder builder = new StringBuilder(operation.Name); if (operation.Parameters.Count > 0) { builder.Append("?"); foreach (var parameter in operation.Parameters) { builder.Append(parameter.Name); builder.Append("={"); builder.Append(parameter.Name); builder.Append("}&"); } builder.Remove(builder.Length - 1, 1); } return(builder.ToString()); }
private void GenerateInvokeOperationDeclaration(DomainOperationEntry domainOperationEntry, InvokeKind invokeKind) { // First generate custom attributes for the qery method IEnumerable <Attribute> methodAttributes = domainOperationEntry.Attributes.Cast <Attribute>(); this.GenerateAttributes(methodAttributes); string invokeOperationReturnTypeName = this.GetInvokeMethodReturnTypeName(domainOperationEntry, invokeKind); var name = domainOperationEntry.Name; if (invokeKind == InvokeKind.Async) { name = name + "Async"; } this.Write("public "); this.Write(this.ToStringHelper.ToStringWithCulture(invokeOperationReturnTypeName)); this.Write(" "); this.Write(this.ToStringHelper.ToStringWithCulture(name)); this.Write("(\r\n"); this.GenerateParameterDeclaration(domainOperationEntry.Parameters, true); if (invokeKind == InvokeKind.WithCallback) { if (domainOperationEntry.Parameters.Count() > 0) { this.Write(", "); } this.Write("Action<"); this.Write(this.ToStringHelper.ToStringWithCulture(invokeOperationReturnTypeName)); this.Write("> callback, object userState\r\n"); } this.Write(")\r\n"); }
public async Task InvokeOperation_ServerValidationError() { TestProvider_Scenarios provider = ServerTestHelper.CreateInitializedDomainService <TestProvider_Scenarios>(DomainOperationType.Invoke); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(typeof(TestProvider_Scenarios)); DomainOperationEntry incrementBid1ForAByMethod = serviceDescription.GetInvokeOperation("IncrementBid1ForABy"); Assert.IsNotNull(incrementBid1ForAByMethod); TestDomainServices.A inputA = new TestDomainServices.A() { BID1 = 1 }; var invokeResult = await provider.InvokeAsync(new InvokeDescription(incrementBid1ForAByMethod, new object[] { inputA, 2 }), CancellationToken.None); Assert.IsNull(invokeResult.Result); Assert.IsNotNull(invokeResult.ValidationErrors); Assert.AreEqual(2, invokeResult.ValidationErrors.Count); Assert.AreEqual("The field delta must be between 5 and 10.", invokeResult.ValidationErrors.ElementAt(0).ErrorMessage); Assert.AreEqual("The RequiredString field is required.", invokeResult.ValidationErrors.ElementAt(1).ErrorMessage); }
public void RequiresRoleAttribute_Authorize_MultipleAttributes_Allowed() { IPrincipal user = this.CreateIPrincipal("user1", "role1", "role4"); // Instantiate a new DomainService to use for an Invoke using (RequiresRoleTestService testDomainService = new RequiresRoleTestService()) { testDomainService.Initialize(new DomainServiceContext(new MockDataService(user), DomainOperationType.Invoke)); // Get a DomainServiceDescription for that same domain service DomainServiceDescription description = DomainServiceDescription.GetDescription(typeof(RequiresRoleTestService)); // Locate the invoke method DomainOperationEntry invokeEntry = description.DomainOperationEntries.Single(p => p.Name == "Method1"); AuthorizationResult result = testDomainService.IsAuthorized(invokeEntry, entity: null); Assert.AreSame(AuthorizationResult.Allowed, result, "Expected user in role1 and role4 to be allowed against invoke requiring roles (1 or 2) && (3 or 4) in multiple attributes"); } }
internal string GetInvokeMethodReturnTypeName(DomainOperationEntry domainOperationEntry, InvokeKind invokeKind) { Type returnType = CodeGenUtilities.TranslateType(domainOperationEntry.ReturnType); string returnTypeString = (invokeKind == InvokeKind.Async) ? "InvokeResult" : "InvokeOperation"; if (returnType != typeof(void)) { if (!this.RegisterEnumTypeIfNecessary(returnType, domainOperationEntry)) { return(String.Empty); } returnTypeString = returnTypeString + "<" + CodeGenUtilities.GetTypeName(returnType) + ">"; } if (invokeKind == InvokeKind.Async) { returnTypeString = string.Format("System.Threading.Tasks.Task<{0}>", returnTypeString); } return(returnTypeString); }
/// <summary> /// Helper method performs a invoke operation against a given proxy instance. /// </summary> /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param> /// <param name="context">The current context.</param> /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created /// <see cref="DomainServices"/> will be added to.</param> /// <param name="name">The name of the operation to invoke.</param> /// <param name="parameters">The operation parameters.</param> /// <returns>The result of the invoke operation.</returns> /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception> /// <exception cref="ArgumentNullException">if <paramref name="name"/> is null or an empty string.</exception> /// <exception cref="OperationException">if operation errors are thrown during execution of the invoke operation.</exception> public static object Invoke(Type domainService, DomainServiceContext context, IList <DomainService> domainServiceInstances, string name, object[] parameters) { context = new DomainServiceContext(context, DomainOperationType.Invoke); DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(service.GetType()); DomainOperationEntry method = serviceDescription.GetInvokeOperation(name); InvokeDescription invokeDescription = new InvokeDescription(method, parameters); // TODO: Look into removing this blocking Wait var loadResult = service.InvokeAsync(invokeDescription, CancellationToken.None) .GetAwaiter().GetResult(); if (loadResult.HasValidationErrors) { IEnumerable <ValidationResultInfo> operationErrors = loadResult.ValidationErrors.Select(ve => new ValidationResultInfo(ve.ErrorMessage, ve.MemberNames)); throw new OperationException(Resource.DomainServiceProxy_OperationError, operationErrors); } return(loadResult.Result); }
internal static string GetEndOperationReturnType(DomainOperationEntry operation) { string returnTypeName = null; if (operation.Operation == DomainOperation.Query) { if (operation.ReturnType == typeof(void)) { returnTypeName = "OpenRiaServices.DomainServices.Client.QueryResult"; } else { returnTypeName = "OpenRiaServices.DomainServices.Client.QueryResult<" + CodeGenUtilities.GetTypeName(CodeGenUtilities.TranslateType(operation.AssociatedType)) + ">"; } } else { returnTypeName = CodeGenUtilities.GetTypeName(CodeGenUtilities.TranslateType(operation.ReturnType)); } return(returnTypeName); }
public async Task TestDomainService_QueryDirect() { TestDomainServices.LTS.Catalog provider = ServerTestHelper.CreateInitializedDomainService <TestDomainServices.LTS.Catalog>(DomainOperationType.Query); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(provider.GetType()); DomainOperationEntry method = serviceDescription.DomainOperationEntries.Where(p => p.Operation == DomainOperation.Query).First(p => p.Name == "GetProductsByCategory"); QueryDescription qd = new QueryDescription(method, new object[] { 1 }); var queryResult = await provider.QueryAsync <DataTests.AdventureWorks.LTS.Product>(qd, CancellationToken.None); int count = queryResult.Result.Cast <DataTests.AdventureWorks.LTS.Product>().Count(); Assert.AreEqual(32, count); // verify that we can use the same provider to execute another query qd = new QueryDescription(method, new object[] { 2 }); queryResult = await provider.QueryAsync <DataTests.AdventureWorks.LTS.Product>(qd, CancellationToken.None); count = queryResult.Result.Cast <DataTests.AdventureWorks.LTS.Product>().Count(); Assert.AreEqual(43, count); }
/// <summary> /// Validates that the operation entry represents <see cref="IAuthentication{T}.GetUser"/> for use in codegen. /// </summary> /// <param name="doe">The entry to validate</param> /// <param name="userType">The user type. <c>T</c> in <see cref="IAuthentication{T}"/>.</param> /// <returns>Whether the operation entry represents GetUser</returns> private static bool CheckIAuthenticationGetUser(DomainOperationEntry doe, Type userType) { bool implementsGetUser = true; // [Query] // public T GetUser() if (doe.Operation != DomainOperation.Query) { implementsGetUser = false; } if (doe.ReturnType != userType) { implementsGetUser = false; } if (doe.Parameters.Any()) { implementsGetUser = false; } return(implementsGetUser); }
public void TestDomainService_QueryDirect() { TestDomainServices.LTS.Catalog provider = ServerTestHelper.CreateInitializedDomainService <TestDomainServices.LTS.Catalog>(DomainOperationType.Query); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(provider.GetType()); DomainOperationEntry method = serviceDescription.DomainOperationEntries.Where(p => p.Operation == DomainOperation.Query).First(p => p.Name == "GetProductsByCategory"); QueryDescription qd = new QueryDescription(method, new object[] { 1 }); int totalCount; IEnumerable <ValidationResult> validationErrors; IEnumerable result = provider.Query(qd, out validationErrors, out totalCount); int count = result.Cast <DataTests.AdventureWorks.LTS.Product>().Count(); Assert.AreEqual(32, count); // verify that we can use the same provider to execute another query qd = new QueryDescription(method, new object[] { 2 }); result = provider.Query(qd, out validationErrors, out totalCount); count = result.Cast <DataTests.AdventureWorks.LTS.Product>().Count(); Assert.AreEqual(43, count); }
public async Task ServerValidation_InvokeOperation() { TestDomainServices.TestProvider_Scenarios service = ServerTestHelper.CreateInitializedDomainService <TestDomainServices.TestProvider_Scenarios>(DomainOperationType.Invoke); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(service.GetType()); DomainOperationEntry method = serviceDescription.DomainOperationEntries.Single(p => p.Name == "InvokeOperationWithParamValidation"); InvokeDescription invokeDescription = new InvokeDescription(method, new object[] { -3, "ABC", new TestDomainServices.CityWithCacheData() }); var invokeResult = await service.InvokeAsync(invokeDescription, CancellationToken.None); Assert.IsNotNull(invokeResult.ValidationErrors); Assert.AreEqual(2, invokeResult.ValidationErrors.Count()); ValidationResult error = invokeResult.ValidationErrors.ElementAt(0); Assert.AreEqual("The field a must be between 0 and 10.", error.ErrorMessage); Assert.AreEqual("a", error.MemberNames.Single()); error = invokeResult.ValidationErrors.ElementAt(1); Assert.AreEqual("The field b must be a string with a maximum length of 2.", error.ErrorMessage); Assert.AreEqual("b", error.MemberNames.Single()); }
/// <summary> /// Helper method performs a query operation against a given proxy instance. /// </summary> /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param> /// <param name="context">The current context.</param> /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created /// <see cref="DomainServices"/> will be added to.</param> /// <param name="queryName">The name of the query to invoke.</param> /// <param name="parameters">The query parameters.</param> /// <returns>The query results. May be null if there are no query results.</returns> /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception> /// <exception cref="ArgumentNullException">if <paramref name="queryName"/> is null or an empty string.</exception> /// <exception cref="InvalidOperationException">if no match query operation exists on the <paramref name="context"/>.</exception> /// <exception cref="OperationException">if operation errors are thrown during execution of the query operation.</exception> public static IEnumerable Query(Type domainService, DomainServiceContext context, IList <DomainService> domainServiceInstances, string queryName, object[] parameters) { context = new DomainServiceContext(context, DomainOperationType.Query); DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(service.GetType()); DomainOperationEntry queryOperation = serviceDescription.GetQueryMethod(queryName); if (queryOperation == null) { string errorMessage = string.Format( CultureInfo.InvariantCulture, Resource.DomainServiceProxy_QueryOperationNotFound, queryName, domainService); throw new InvalidOperationException(errorMessage); } IEnumerable <ValidationResult> validationErrors; object[] parameterValues = parameters ?? Array.Empty <object>(); QueryDescription queryDescription = new QueryDescription(queryOperation, parameterValues); // TODO: Look into removing this blocking Wait var actualMethod = s_queryAsync.MakeGenericMethod(queryDescription.Method.AssociatedType); var queryResult = ((ValueTask <ServiceQueryResult>)actualMethod.Invoke(service, new object[] { queryDescription, CancellationToken.None })) .GetAwaiter().GetResult(); validationErrors = queryResult.ValidationErrors; var result = queryResult.Result; if (validationErrors != null && validationErrors.Any()) { IEnumerable <ValidationResultInfo> operationErrors = validationErrors.Select(ve => new ValidationResultInfo(ve.ErrorMessage, ve.MemberNames)); throw new OperationException(Resource.DomainServiceProxy_OperationError, operationErrors); } return(result); }
/// <summary> /// If the query operation has a result limit, this operation will compose Take(limit) on top /// of the specified results. /// </summary> /// <param name="results">The results that may need to be limited.</param> /// <param name="queryOperation">The query operation that was invoked to get the results.</param> /// <param name="limitedResults">The limited results. It will be <value>null</value> if there is no result limit.</param> /// <returns>True if a limited result query is returned, false otherwise.</returns> internal static bool TryComposeWithLimit(IEnumerable results, DomainOperationEntry queryOperation, out IEnumerable limitedResults) { int limit = ((QueryAttribute)queryOperation.OperationAttribute).ResultLimit; if (limit > 0) { IQueryable queryableResult = results.AsQueryable(); // Compose Take(limit) over the results. IQueryable limitQuery = Array.CreateInstance(queryOperation.AssociatedType, 0).AsQueryable(); limitQuery = limitQuery.Provider.CreateQuery( Expression.Call( typeof(Queryable), "Take", new Type[] { limitQuery.ElementType }, limitQuery.Expression, Expression.Constant(limit))); limitedResults = QueryComposer.Compose(queryableResult, limitQuery); return true; } limitedResults = null; return false; }
public void DomainServiceWithMultipleValidOnlineMethods() { DomainServiceDescription description = DomainServiceDescription.GetDescription(typeof(OnlineMethod_ValidProvider_MultipleMethods)); Assert.IsNotNull(description); // verify GetOnlineMethod returns the correct DomainOperationEntry DomainOperationEntry returnedMethod = description.GetInvokeOperation("Process_VoidReturn"); Assert.IsNotNull(returnedMethod); Assert.AreEqual(DomainOperation.Invoke, returnedMethod.Operation); Assert.AreEqual("Process_VoidReturn", returnedMethod.Name); // verify GetOnlineMethods return all the invoke operations on this provider IEnumerable <DomainOperationEntry> returnedMethods = description.DomainOperationEntries.Where(p => p.Operation == DomainOperation.Invoke); Assert.IsNotNull(returnedMethods); Assert.AreEqual(10, returnedMethods.Count()); Assert.IsTrue(returnedMethods.Any(p => p.Name == "Process_EntitiesAndSimpleParams")); Assert.IsTrue(returnedMethods.Any(p => p.Name == "Process_Return_EntityListParam")); }
/// <summary> /// Validates that the operation entry represents <see cref="IAuthentication{T}.UpdateUser"/> for use in codegen. /// </summary> /// <param name="doe">The entry to validate</param> /// <param name="userType">The user type. <c>T</c> in <see cref="IAuthentication{T}"/>.</param> /// <returns>Whether the operation entry represents UpdateUser</returns> private static bool CheckIAuthenticationUpdateUser(DomainOperationEntry doe, Type userType) { bool implementsUpdateUser = true; // [Update] // public void UpdateUser(T user) if (doe.Operation != DomainOperation.Update) { implementsUpdateUser = false; } if (doe.ReturnType != typeof(void)) { implementsUpdateUser = false; } if ((doe.Parameters.Count() != 1) || (doe.Parameters[0].ParameterType != userType)) { implementsUpdateUser = false; } return(implementsUpdateUser); }
private void GenerateCustomMethodProperties(DomainOperationEntry customMethod) { this.Write("[System.ComponentModel.DataAnnotations.Display(AutoGenerateField=false)]\r\npublic " + "bool Can"); this.Write(this.ToStringHelper.ToStringWithCulture(customMethod.Name)); this.Write("\r\n{\r\n\tget\r\n\t{\r\n\t\treturn base.CanInvokeAction(\""); this.Write(this.ToStringHelper.ToStringWithCulture(customMethod.Name)); this.Write("\");\r\n\t}\r\n}\r\n\r\n[System.ComponentModel.DataAnnotations.Display(AutoGenerateField=fa" + "lse)]\r\npublic bool Is"); this.Write(this.ToStringHelper.ToStringWithCulture(customMethod.Name)); this.Write("Invoked\r\n{\r\n\tget\r\n\t{\r\n\t\treturn base.IsActionInvoked(\""); this.Write(this.ToStringHelper.ToStringWithCulture(customMethod.Name)); this.Write("\");\r\n\t}\r\n}\r\n"); }
public void TestDomainService_QueryDirect_Throws() { MockDomainService_SelectThrows provider = ServerTestHelper.CreateInitializedDomainService <MockDomainService_SelectThrows>(DomainOperationType.Query); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(provider.GetType()); DomainOperationEntry method = serviceDescription.DomainOperationEntries.First(p => p.Name == "GetEntities" && p.Operation == DomainOperation.Query); QueryDescription qd = new QueryDescription(method, new object[0]); int totalCount; IEnumerable <ValidationResult> validationErrors; ExceptionHelper.ExpectException <Exception>(delegate { try { provider.Query(qd, out validationErrors, out totalCount); } catch (TargetInvocationException ex) { throw ex.InnerException; } }, "Test"); }
public async Task ServerValidation_Query() { TestDomainServices.TestProvider_Scenarios service = ServerTestHelper.CreateInitializedDomainService <TestDomainServices.TestProvider_Scenarios>(DomainOperationType.Query); DomainServiceDescription serviceDescription = DomainServiceDescription.GetDescription(service.GetType()); DomainOperationEntry method = serviceDescription.DomainOperationEntries.Single(p => p.Name == "QueryWithParamValidation"); QueryDescription qd = new QueryDescription(method, new object[] { -1, "ABC" }); var queryResult = await service.QueryAsync <TestDomainServices.A>(qd, CancellationToken.None); Assert.IsNotNull(queryResult.ValidationErrors); Assert.AreEqual(2, queryResult.ValidationErrors.Count()); ValidationResult error = queryResult.ValidationErrors.ElementAt(0); Assert.AreEqual("The field a must be between 0 and 10.", error.ErrorMessage); Assert.AreEqual("a", error.MemberNames.Single()); error = queryResult.ValidationErrors.ElementAt(1); Assert.AreEqual("The field b must be a string with a maximum length of 2.", error.ErrorMessage); Assert.AreEqual("b", error.MemberNames.Single()); }
internal string GetInvokeMethodReturnTypeName(DomainOperationEntry domainOperationEntry, InvokeKind invokeKind) { Type returnType = CodeGenUtilities.TranslateType(domainOperationEntry.ReturnType); string returnTypeString = (invokeKind == InvokeKind.Async) ? "InvokeResult" : "InvokeOperation"; if (returnType != typeof (void)) { if (!this.RegisterEnumTypeIfNecessary(returnType, domainOperationEntry)) { return String.Empty; } returnTypeString = returnTypeString + "<" + CodeGenUtilities.GetTypeName(returnType) + ">"; } if (invokeKind == InvokeKind.Async) returnTypeString = string.Format("System.Threading.Tasks.Task<{0}>", returnTypeString); return returnTypeString; }
private void GenerateContractMethod(DomainOperationEntry operation) { this.Write("[OpenRiaServices.DomainServices.Client.HasSideEffects("); this.Write(this.ToStringHelper.ToStringWithCulture(DomainContextGenerator.OperationHasSideEffects(operation).ToString().ToLower())); this.Write(")]\r\n"); this.GenerateContractMethodAttributes(operation.Name); this.Write("System.IAsyncResult Begin"); this.Write(this.ToStringHelper.ToStringWithCulture(operation.Name)); this.Write("(\r\n"); foreach (DomainOperationParameter parameter in operation.Parameters) { Type parameterType = CodeGenUtilities.TranslateType(parameter.ParameterType); this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetTypeName(parameterType))); this.Write(" "); this.Write(this.ToStringHelper.ToStringWithCulture(parameter.Name)); this.Write(",\r\n"); } this.Write("System.AsyncCallback callback, object asyncState);\r\n"); string returnTypeName = CSharpDomainContextGenerator.GetEndOperationReturnType(operation); this.Write("\t\t\r\n"); this.Write(this.ToStringHelper.ToStringWithCulture(returnTypeName)); this.Write(" End"); this.Write(this.ToStringHelper.ToStringWithCulture(operation.Name)); this.Write("(System.IAsyncResult result);\r\n"); }
private string GenerateServiceOpMethodBody(DomainOperationEntry domainOperationEntry, string methodName) { string parameterDictionaryName = "null"; DomainOperationParameter[] domainOperationEntryParameters = domainOperationEntry.Parameters.ToArray(); if(domainOperationEntryParameters.Length > 0) { parameterDictionaryName = "parameters"; this.Write("Dictionary<string, object> "); this.Write(this.ToStringHelper.ToStringWithCulture(parameterDictionaryName)); this.Write(" = new Dictionary<string, object>();\r\n"); foreach(DomainOperationParameter paramInfo in domainOperationEntryParameters) { if (!this.RegisterEnumTypeIfNecessary(paramInfo.ParameterType, domainOperationEntry)) { return String.Empty; } string paramName = CodeGenUtilities.GetSafeName(paramInfo.Name); this.Write(this.ToStringHelper.ToStringWithCulture(parameterDictionaryName)); this.Write(".Add(\""); this.Write(this.ToStringHelper.ToStringWithCulture(paramName)); this.Write("\", "); this.Write(this.ToStringHelper.ToStringWithCulture(paramName)); this.Write(");\r\n"); } } this.Write("this.ValidateMethod(\""); this.Write(this.ToStringHelper.ToStringWithCulture(methodName)); this.Write("\", "); this.Write(this.ToStringHelper.ToStringWithCulture(parameterDictionaryName)); this.Write(");\r\n"); return parameterDictionaryName; }
private void GenerateInvokeMethodReturn(DomainOperationEntry domainOperationEntry, string parameterDictionaryString, InvokeKind invokeKind) { InvokeAttribute invokeAttribute = (InvokeAttribute)domainOperationEntry.OperationAttribute; string returnTypeNameString = CodeGenUtilities.GetTypeName(CodeGenUtilities.TranslateType(domainOperationEntry.ReturnType)); if(invokeKind == InvokeKind.Async) { returnTypeNameString = (domainOperationEntry.ReturnType == typeof(void)) ? string.Empty : string.Format("<{0}>", returnTypeNameString); this.Write("return this.InvokeOperationAsync"); this.Write(this.ToStringHelper.ToStringWithCulture(returnTypeNameString)); this.Write("(\""); this.Write(this.ToStringHelper.ToStringWithCulture(domainOperationEntry.Name)); this.Write("\", "); this.Write(this.ToStringHelper.ToStringWithCulture(parameterDictionaryString)); this.Write(", \r\n"); this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetBooleanString(invokeAttribute.HasSideEffects, true))); this.Write(");\r\n"); } else { this.Write("return this."); this.Write(this.ToStringHelper.ToStringWithCulture(this.GetInvokeMethodReturnTypeName(domainOperationEntry, invokeKind))); this.Write("(\""); this.Write(this.ToStringHelper.ToStringWithCulture(domainOperationEntry.Name)); this.Write("\", typeof("); this.Write(this.ToStringHelper.ToStringWithCulture(returnTypeNameString)); this.Write("), "); this.Write(this.ToStringHelper.ToStringWithCulture(parameterDictionaryString)); this.Write(", \r\n"); this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetBooleanString(invokeAttribute.HasSideEffects, true))); this.Write(",\r\n"); if(invokeKind == InvokeKind.WithCallback) { this.Write("callback, userState);\r\n"); } else { this.Write("null, null);\r\n"); } } }
private void GenerateInvokeMethodBody(DomainOperationEntry domainOperationEntry, InvokeKind invokeKind) { string parameterDictionaryString = this.GenerateServiceOpMethodBody(domainOperationEntry, domainOperationEntry.Name); this.GenerateInvokeMethodReturn(domainOperationEntry, parameterDictionaryString, invokeKind); }
/// <summary> /// Generates a custom method. /// </summary> /// <param name="domainMethod">The custom method to be generated.</param> protected virtual void GenerateCustomMethod(DomainOperationEntry domainMethod) { this.Write("public void "); this.Write(this.ToStringHelper.ToStringWithCulture(domainMethod.Name)); this.Write("("); List<string> invokeParams = new List<string>(); DomainOperationParameter[] paramInfos = domainMethod.Parameters.ToArray(); for(int i = 0; i < paramInfos.Length; i++) { DomainOperationParameter paramInfo = paramInfos[i]; string paramTypeName = CodeGenUtilities.GetTypeName(CodeGenUtilities.TranslateType(paramInfo.ParameterType)); this.Write(this.ToStringHelper.ToStringWithCulture(paramTypeName)); this.Write(" "); this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetSafeName(paramInfo.Name))); if(i + 1 < paramInfos.Length) { this.Write(", "); } if(i > 0) { invokeParams.Add(paramInfo.Name); } } this.Write(")\r\n"); this.GenerateOpeningBrace(); this.Write(this.ToStringHelper.ToStringWithCulture(paramInfos[0].Name)); this.Write("."); this.Write(this.ToStringHelper.ToStringWithCulture(domainMethod.Name)); this.Write("("); for(int i = 0; i < invokeParams.Count; i ++) { this.Write(this.ToStringHelper.ToStringWithCulture(invokeParams[i])); if(i + 1 < invokeParams.Count) { this.Write(", "); } } this.Write(");\r\n"); this.GenerateClosingBrace(); }
internal bool CanGenerateDomainOperationEntry(DomainOperationEntry domainOperationEntry) { string methodName = (domainOperationEntry.Operation == DomainOperation.Query) ? domainOperationEntry.Name : domainOperationEntry.Name + QuerySuffix; // Check each parameter type to see if is enum DomainOperationParameter[] paramInfos = domainOperationEntry.Parameters.ToArray(); for (int i = 0; i < paramInfos.Length; i++) { DomainOperationParameter paramInfo = paramInfos[i]; // If this is an enum type, we need to ensure it is either shared or // can be generated. Failure logs an error. The test for legality also causes // the enum to be generated if required. Type enumType = TypeUtility.GetNonNullableType(paramInfo.ParameterType); if (enumType.IsEnum) { string errorMessage = null; if (!this.ClientCodeGenerator.CanExposeEnumType(enumType, out errorMessage)) { this.ClientCodeGenerator.CodeGenerationHost.LogError(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Domain_Op_Enum_Error, domainOperationEntry.Name, this.DomainContextTypeName, enumType.FullName, errorMessage)); return false; } else { // Register use of this enum type, which could cause deferred generation this.ClientCodeGenerator.AddEnumTypeToGenerate(enumType); } } } return true; }
/// <summary> /// Generates an invoke operation. /// </summary> /// <param name="domainOperationEntry">The invoke operation to be generated.</param> /// <param name="generateCallback">If set to true, causes callback to be generated on the method.</param> protected virtual void GenerateInvokeOperation(DomainOperationEntry domainOperationEntry, bool generateCallback) { var invokeKind = generateCallback ? (InvokeKind.WithCallback) : (InvokeKind.WithoutCallback); GenerateInvokeOperation(domainOperationEntry, invokeKind); }
internal static bool OperationHasSideEffects(DomainOperationEntry operation) { if (operation.Operation == DomainOperation.Query) { return ((QueryAttribute)operation.OperationAttribute).HasSideEffects; } else if (operation.Operation == DomainOperation.Invoke) { return ((InvokeAttribute)operation.OperationAttribute).HasSideEffects; } return false; }
/// <summary> /// Initializes a new instance of the <see cref="QueryDescription"/> class with the specified /// <see cref="DomainOperationEntry"/>, parameter values, flag indicating whether /// to evaluate and include total entity count in the result and (optional) query to compose over /// the results. /// </summary> /// <param name="domainOperationEntry">The query operation to be processed</param> /// <param name="parameterValues">Parameter values for the method if it requires any</param> /// <param name="includeTotalCount">Flag to indicate that total entity count is required</param> /// <param name="query">The query to compose over the results</param> public QueryDescription(DomainOperationEntry domainOperationEntry, object[] parameterValues, bool includeTotalCount, IQueryable query) : this(domainOperationEntry, parameterValues) { this._query = query; this._includeTotalCount = includeTotalCount; }
private void GenerateEntityQueryMethodDeclaration(DomainOperationEntry domainOperationEntry, string queryMethodName) { // First generate custom attributes for the qery method IEnumerable<Attribute> methodAttributes = domainOperationEntry.Attributes.Cast<Attribute>(); this.GenerateAttributes(methodAttributes); this.Write("public EntityQuery<"); this.Write(this.ToStringHelper.ToStringWithCulture(this.GetEntityQueryMethodElementReturnTypeName(domainOperationEntry))); this.Write("> "); this.Write(this.ToStringHelper.ToStringWithCulture(queryMethodName)); this.Write("("); this.GenerateParameterDeclaration(domainOperationEntry.Parameters.AsEnumerable(), true); this.Write(")\r\n"); }
public void InsertEntity(ServiceContext_CurrentOperation_Entity entity) { LastOperation = this.ServiceContext.Operation; }
internal static string GetEndOperationReturnType(DomainOperationEntry operation) { string returnTypeName = null; if (operation.Operation == DomainOperation.Query) { if (operation.ReturnType == typeof (void)) { returnTypeName = "OpenRiaServices.DomainServices.Client.QueryResult"; } else { returnTypeName = "OpenRiaServices.DomainServices.Client.QueryResult<" + CodeGenUtilities.GetTypeName(CodeGenUtilities.TranslateType(operation.AssociatedType)) + ">"; } } else { returnTypeName = CodeGenUtilities.GetTypeName(CodeGenUtilities.TranslateType(operation.ReturnType)); } return returnTypeName; }
/// <summary> /// Generates an async invoke operation. /// </summary> /// <param name="domainOperationEntry">The invoke operation to be generated.</param> /// <param name="invokeKind">The type of invoke operation to be generated.</param> protected virtual void GenerateInvokeOperation(DomainOperationEntry domainOperationEntry, InvokeKind invokeKind) { this.GenerateInvokeOperationDeclaration(domainOperationEntry, invokeKind); this.GenerateOpeningBrace(); this.GenerateInvokeMethodBody(domainOperationEntry, invokeKind); this.GenerateClosingBrace(); }
private void GenerateCustomMethod(string customMethodName, DomainOperationEntry customMethod) { this.ClientProxyGenerator.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.EntityCodeGen_Generating_InvokeMethod, customMethodName)); // ---------------------------------------------------------------- // Method decl // ---------------------------------------------------------------- CodeMemberMethod method = new CodeMemberMethod(); method.Name = customMethodName; method.Attributes = MemberAttributes.Public | MemberAttributes.Final; // The custom method parameter list is the same as the domain operation entries -- except for the first parameter // which is the entity. We omit that first parameter in code gen DomainOperationParameter[] paramInfos = customMethod.Parameters.ToArray(); // Generate <summary> doc comment for the custom method body string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Entity_Custom_Method_Summary_Comment, customMethodName); method.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp)); // Generate <param> doc comment for all the parameters for (int i = 1; i < paramInfos.Length; ++i) { comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Entity_Custom_Method_Parameter_Comment, paramInfos[i].Name); method.Comments.AddRange(CodeGenUtilities.GenerateParamCodeComment(paramInfos[i].Name, comment, this.ClientProxyGenerator.IsCSharp)); } // Propagate custom validation attributes from the DomainOperationEntry to this custom method var methodAttributes = customMethod.Attributes.Cast<Attribute>().ToList(); CustomAttributeGenerator.GenerateCustomAttributes( this.ClientProxyGenerator, this._proxyClass, ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeMethod, ex.Message, method.Name, this._proxyClass.Name, ex.InnerException.Message), methodAttributes, method.CustomAttributes, method.Comments); // Add [CustomMethod("...")] property var customMethodAttribute = customMethod.OperationAttribute as EntityActionAttribute; bool allowMultipleInvocations = customMethodAttribute != null && customMethodAttribute.AllowMultipleInvocations; method.CustomAttributes.Add( new CodeAttributeDeclaration( CodeGenUtilities.GetTypeReference(TypeConstants.EntityActionAttributeFullName, (string)this._proxyClass.UserData["Namespace"], false), new CodeAttributeArgument(new CodePrimitiveExpression(customMethodName)), new CodeAttributeArgument("AllowMultipleInvocations", new CodePrimitiveExpression(allowMultipleInvocations)) )); // ---------------------------------------------------------------- // generate custom method body: // this.OnMethodNameInvoking(params); // base.Invoke(methodName, params); // this.OnMethodNameInvoked(); // ---------------------------------------------------------------- List<CodeExpression> invokeParams = new List<CodeExpression>(); invokeParams.Add(new CodePrimitiveExpression(customMethodName)); // Create an expression for each parameter, and also use this loop to // propagate the custom attributes for each parameter in the DomainOperationEntry to the custom method. for (int i = 1; i < paramInfos.Length; ++i) { DomainOperationParameter paramInfo = paramInfos[i]; // build up the method parameter signature from the DomainOperationEntry.MethodInfo CodeParameterDeclarationExpression paramDecl = new CodeParameterDeclarationExpression( CodeGenUtilities.GetTypeReference( CodeGenUtilities.TranslateType(paramInfo.ParameterType), this.ClientProxyGenerator, this._proxyClass), paramInfo.Name); // Propagate parameter level validation attributes from custom operation entry. IEnumerable<Attribute> paramAttributes = paramInfo.Attributes.Cast<Attribute>(); string commentHeader = string.Format( CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_Parameter_FailedToGenerate, paramInfo.Name); CustomAttributeGenerator.GenerateCustomAttributes( this.ClientProxyGenerator, this._proxyClass, ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeMethodParameter, ex.Message, paramDecl.Name, method.Name, this._proxyClass.Name, ex.InnerException.Message), paramAttributes, paramDecl.CustomAttributes, method.Comments, commentHeader); method.Parameters.Add(paramDecl); // build up the invoke call parameters invokeParams.Add(new CodeVariableReferenceExpression(paramInfo.Name)); } // generate 'OnCustomMethodInvoked/Invoking' string methodInvokingName = customMethodName + "Invoking"; string methodInvokedName = customMethodName + "Invoked"; this._notificationMethodGen.AddMethodFor(methodInvokingName, method.Parameters, null); this._notificationMethodGen.AddMethodFor(methodInvokedName, null); method.Statements.Add(this._notificationMethodGen.GetMethodInvokeExpressionStatementFor(methodInvokingName)); method.Statements.Add( new CodeExpressionStatement( new CodeMethodInvokeExpression( new CodeBaseReferenceExpression(), "InvokeAction", invokeParams.ToArray()))); method.Statements.Add(this._notificationMethodGen.GetMethodInvokeExpressionStatementFor(methodInvokedName)); this._proxyClass.Members.Add(method); // ---------------------------------------------------------------- // generate Is<CustomMethod>Invoked property: // [Display(AutoGenerateField=false)] // public bool IsMyCustomMethodInvoked { get { base.IsActionInvoked(methodName);}} // ---------------------------------------------------------------- CodeMemberProperty invokedProperty = new CodeMemberProperty(); invokedProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final; invokedProperty.HasGet = true; invokedProperty.HasSet = false; invokedProperty.Type = new CodeTypeReference(typeof(bool)); invokedProperty.GetStatements.Add(new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeBaseReferenceExpression(), "IsActionInvoked", new CodeExpression[] { new CodeArgumentReferenceExpression("\"" + customMethodName + "\"") }))); invokedProperty.Name = GetIsInvokedPropertyName(customMethodName); // Generate <summary> doc comment comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Entity_IsInvoked_Property_Summary_Comment, customMethodName); invokedProperty.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp)); CodeAttributeDeclaration displayAttribute = CodeGenUtilities.CreateDisplayAttributeDeclaration(this.ClientProxyGenerator, this._proxyClass); invokedProperty.CustomAttributes.Add(displayAttribute); this._proxyClass.Members.Add(invokedProperty); }
private void GenerateInvokeOperationDeclaration(DomainOperationEntry domainOperationEntry, InvokeKind invokeKind) { // First generate custom attributes for the qery method IEnumerable<Attribute> methodAttributes = domainOperationEntry.Attributes.Cast<Attribute>(); this.GenerateAttributes(methodAttributes); string invokeOperationReturnTypeName = this.GetInvokeMethodReturnTypeName(domainOperationEntry, invokeKind); var name = domainOperationEntry.Name; if(invokeKind == InvokeKind.Async) name = name + "Async"; this.Write("public "); this.Write(this.ToStringHelper.ToStringWithCulture(invokeOperationReturnTypeName)); this.Write(" "); this.Write(this.ToStringHelper.ToStringWithCulture(name)); this.Write("(\r\n"); this.GenerateParameterDeclaration(domainOperationEntry.Parameters, true); if(invokeKind == InvokeKind.WithCallback) { if(domainOperationEntry.Parameters.Count() > 0) { this.Write(", "); } this.Write("Action<"); this.Write(this.ToStringHelper.ToStringWithCulture(invokeOperationReturnTypeName)); this.Write("> callback, object userState\r\n"); } this.Write(")\r\n"); }
private void GenerateEntityQueryMethodBody(DomainOperationEntry domainOperationEntry, string queryMethodName) { string parameterDictionaryName = this.GenerateServiceOpMethodBody(domainOperationEntry, queryMethodName); this.GenerateEntityQueryMethodReturn(domainOperationEntry, parameterDictionaryName); }
/// <summary> /// Builds the default URI temaplate to be used for side-effecting (POST) operations. /// </summary> /// <param name="operation">Domain operation.</param> /// <returns>string representing the default URI temaplate.</returns> private static string BuildDefaultUriTemplate(DomainOperationEntry operation) { StringBuilder builder = new StringBuilder(operation.Name); if (operation.Parameters.Count > 0) { builder.Append("?"); foreach (var parameter in operation.Parameters) { builder.Append(parameter.Name); builder.Append("={"); builder.Append(parameter.Name); builder.Append("}&"); } builder.Remove(builder.Length - 1, 1); } return builder.ToString(); }
private void GenerateEntityQueryMethodReturn(DomainOperationEntry domainOperationEntry, string parameterDictionaryName) { QueryAttribute queryAttribute = (QueryAttribute)domainOperationEntry.OperationAttribute; this.Write("return base.CreateQuery<"); this.Write(this.ToStringHelper.ToStringWithCulture(this.GetEntityQueryMethodElementReturnTypeName(domainOperationEntry))); this.Write(">(\""); this.Write(this.ToStringHelper.ToStringWithCulture(domainOperationEntry.Name)); this.Write("\", "); this.Write(this.ToStringHelper.ToStringWithCulture(parameterDictionaryName)); this.Write(", "); this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetBooleanString(queryAttribute.HasSideEffects, true))); this.Write(", "); this.Write(this.ToStringHelper.ToStringWithCulture(CodeGenUtilities.GetBooleanString(queryAttribute.IsComposable, true))); this.Write(");\r\n"); }
private string GetEntityQueryMethodElementReturnTypeName(DomainOperationEntry domainOperationEntry) { Type entityType = TypeUtility.GetElementType(domainOperationEntry.ReturnType); return CodeGenUtilities.GetTypeName(entityType); }
/// <summary> /// Generates a query method. /// </summary> /// <param name="domainOperationEntry">The query method to be generated.</param> protected virtual void GenerateQueryMethod(DomainOperationEntry domainOperationEntry) { string queryMethodName = domainOperationEntry.Name + "Query"; this.GenerateEntityQueryMethodDeclaration(domainOperationEntry, queryMethodName); this.GenerateOpeningBrace(); this.GenerateEntityQueryMethodBody(domainOperationEntry, queryMethodName); this.GenerateClosingBrace(); }
internal List<Attribute> GetContractServiceKnownTypes(DomainOperationEntry operation, HashSet<Type> registeredTypes) { List<Attribute> knownTypeAttributes = new List<Attribute>(); foreach (DomainOperationParameter parameter in operation.Parameters) { Type t = CodeGenUtilities.TranslateType(parameter.ParameterType); // All Nullable<T> types are unwrapped to the underlying non-nullable, because // that is they type we need to represent, not typeof(Nullable<T>) t = TypeUtility.GetNonNullableType(t); if (TypeUtility.IsPredefinedListType(t) || TypeUtility.IsComplexTypeCollection(t)) { Type elementType = TypeUtility.GetElementType(t); if (elementType != null) { t = elementType.MakeArrayType(); } } // Check if the type is a simple type or already registered if (registeredTypes.Contains(t) || !this.TypeRequiresRegistration(t)) { continue; } // Record the type to prevent redundant [ServiceKnownType]'s. // This loop executes within a larger loop over multiple // DomainOperationEntries that may have already processed it. registeredTypes.Add(t); // If we determine we need to generate this enum type on the client, // then we need to register that intent and conjure a virtual type // here in our list of registered types to account for the fact it // could get a different root namespace on the client. if (t.IsEnum && this.ClientCodeGenerator.NeedToGenerateEnumType(t)) { // Request deferred generation of the enum this.ClientCodeGenerator.AddEnumTypeToGenerate(t); // Compose a virtual type that will reflect the correct namespace // on the client when the [ServiceKnownType] is created. t = new VirtualType(t.Name, CodeGenUtilities.TranslateNamespace(t), t.Assembly, t.BaseType); } knownTypeAttributes.Add(new ServiceKnownTypeAttribute(t)); } return knownTypeAttributes; }
public IQueryable<ServiceContext_CurrentOperation_Entity> GetEntities() { LastOperation = this.ServiceContext.Operation; return null; }
/// <summary> /// Create operation corresponding to given DomainService query operation. /// </summary> /// <param name="declaringContract">Contract to which operation will belong.</param> /// <param name="operation">DomainService query operation.</param> /// <returns>Created operation.</returns> private static OperationDescription CreateQueryOperationDescription(ContractDescription declaringContract, DomainOperationEntry operation) { OperationDescription operationDesc = ODataEndpointFactory.CreateOperationDescription(declaringContract, operation); // Change the return type to QueryResult<TEntity>. operationDesc.Messages[1].Body.ReturnValue.Type = typeof(IEnumerable<>).MakeGenericType(operation.AssociatedType); return operationDesc; }
public string Echo() { LastOperation = this.ServiceContext.Operation; return "echo"; }
/// <summary> /// Create operation corresponding to given DomainService operation. /// </summary> /// <param name="declaringContract">Contract to which operation will belong.</param> /// <param name="operation">DomainService operation.</param> /// <returns>Created operation.</returns> private static OperationDescription CreateOperationDescription(ContractDescription declaringContract, DomainOperationEntry operation) { OperationDescription operationDesc = new OperationDescription(operation.Name, declaringContract); // Propagate behaviors. foreach (IOperationBehavior behavior in operation.Attributes.OfType<IOperationBehavior>()) { operationDesc.Behaviors.Add(behavior); } // Add standard web behaviors behaviors. if ((operation.Operation == DomainOperation.Query && ((QueryAttribute)operation.OperationAttribute).HasSideEffects) || (operation.Operation == DomainOperation.Invoke && ((InvokeAttribute)operation.OperationAttribute).HasSideEffects)) { // For operations with side-effects i.e. with WebInvoke attribute, we need to build a default GET like // URI template so that, the parameter processing is taken care of by the WebHttpBehavior selector. WebInvokeAttribute attrib = ServiceUtils.EnsureBehavior<WebInvokeAttribute>(operationDesc); if (attrib.UriTemplate == null) { attrib.UriTemplate = ODataEndpointFactory.BuildDefaultUriTemplate(operation); } } else { ServiceUtils.EnsureBehavior<WebGetAttribute>(operationDesc); } string action = ServiceUtils.GetRequestMessageAction(declaringContract, operationDesc.Name, null); // Define operation input. MessageDescription inputMessageDesc = new MessageDescription(action, MessageDirection.Input); inputMessageDesc.Body.WrapperName = operationDesc.Name; inputMessageDesc.Body.WrapperNamespace = ServiceUtils.DefaultNamespace; for (int i = 0; i < operation.Parameters.Count; i++) { DomainOperationParameter parameter = operation.Parameters[i]; MessagePartDescription parameterPartDesc = new MessagePartDescription(parameter.Name, ServiceUtils.DefaultNamespace) { Index = i, Type = TypeUtils.GetClientType(parameter.ParameterType) }; inputMessageDesc.Body.Parts.Add(parameterPartDesc); } operationDesc.Messages.Add(inputMessageDesc); // Define operation output. string responseAction = ServiceUtils.GetResponseMessageAction(declaringContract, operationDesc.Name, null); MessageDescription outputMessageDesc = new MessageDescription(responseAction, MessageDirection.Output); outputMessageDesc.Body.WrapperName = operationDesc.Name + "Response"; outputMessageDesc.Body.WrapperNamespace = ServiceUtils.DefaultNamespace; if (operation.ReturnType != typeof(void)) { outputMessageDesc.Body.ReturnValue = new MessagePartDescription(operationDesc.Name + "Result", ServiceUtils.DefaultNamespace) { Type = TypeUtils.GetClientType(operation.ReturnType) }; } operationDesc.Messages.Add(outputMessageDesc); return operationDesc; }