/// <summary> /// Validates that the authentication service implements the <see cref="IAuthentication{T}"/> interface /// naturally for use in codegen. /// </summary> /// <remarks> /// This check ensures no part of the interface was implemented explicitly. /// </remarks> /// <param name="authenticationServiceDescription">The domain service description for the type that implemented /// the <see cref="IAuthentication{T}"/> interface. /// </param> /// <param name="genericIAuthenticationType">The generic version of <see cref="IAuthentication{T}"/> implemented /// by the service type of the <paramref name="authenticationServiceDescription"/>. /// </param> /// <exception cref="InvalidOperationException"> is thrown if the <see cref="IAuthentication{T}"/> interface /// is not correctly implemented. /// </exception> private static void CheckIAuthentication(DomainServiceDescription authenticationServiceDescription, out Type genericIAuthenticationType) { bool implementsLogin = false; bool implementsLogout = false; bool implementsGetUser = false; bool implementsUpdateUser = false; if (!typeof(IAuthentication <>).DefinitionIsAssignableFrom(authenticationServiceDescription.DomainServiceType, out genericIAuthenticationType)) { throw new InvalidOperationException(Resources.ApplicationServices_MustBeIAuth); } Type userType = genericIAuthenticationType.GetGenericArguments()[0]; foreach (DomainOperationEntry doe in authenticationServiceDescription.DomainOperationEntries) { switch (doe.Name) { case "Login": implementsLogin = AuthenticationCodeProcessor.CheckIAuthenticationLogin(doe, userType); break; case "Logout": implementsLogout = AuthenticationCodeProcessor.CheckIAuthenticationLogout(doe, userType); break; case "GetUser": implementsGetUser = AuthenticationCodeProcessor.CheckIAuthenticationGetUser(doe, userType); break; case "UpdateUser": implementsUpdateUser = AuthenticationCodeProcessor.CheckIAuthenticationUpdateUser(doe, userType); break; default: break; } } if (!implementsLogin || !implementsLogout || !implementsGetUser || !implementsUpdateUser) { throw new InvalidOperationException(string.Format( CultureInfo.InstalledUICulture, Resources.ApplicationServices_MustBeIAuthImpl, authenticationServiceDescription.DomainServiceType.Name)); } }
/// <summary> /// See <see cref="CodeProcessor.ProcessGeneratedCode"/>. /// </summary> /// <param name="domainServiceDescription">The domainServiceDescription</param> /// <param name="codeCompileUnit">The codeCompileUnit</param> /// <param name="typeMapping">The typeMapping</param> public override void ProcessGeneratedCode(DomainServiceDescription domainServiceDescription, CodeCompileUnit codeCompileUnit, IDictionary <Type, CodeTypeDeclaration> typeMapping) { // Make sure the provider extends IAuthentication<T> Type genericDomainServiceType; AuthenticationCodeProcessor.CheckIAuthentication(domainServiceDescription, out genericDomainServiceType); Type userEntityType = genericDomainServiceType.GetGenericArguments()[0]; AuthenticationCodeProcessor.CheckIUser(userEntityType); // Implement IPrincipal and IIdentity in the user type CodeTypeDeclaration entityTypeDeclaration; typeMapping.TryGetValue(userEntityType, out entityTypeDeclaration); if (entityTypeDeclaration != null) { CodeTypeReference identityInterfaceTypeReference = new CodeTypeReference(typeof(IIdentity)) { Options = CodeTypeReferenceOptions.GlobalReference }; CodeTypeReference principalInterfaceTypeReference = new CodeTypeReference(typeof(IPrincipal)) { Options = CodeTypeReferenceOptions.GlobalReference }; entityTypeDeclaration.BaseTypes.Add(identityInterfaceTypeReference); entityTypeDeclaration.BaseTypes.Add(principalInterfaceTypeReference); //// //// private string IIdentity.AuthenticationType //// CodeMemberProperty authenticationTypeProperty = new CodeMemberProperty() { Attributes = MemberAttributes.Private | MemberAttributes.Final, HasGet = true, Name = "AuthenticationType", Type = new CodeTypeReference(typeof(string)) }; // get { return string.Empty; } authenticationTypeProperty.GetStatements.Add(new CodeMethodReturnStatement( new CodePropertyReferenceExpression( new CodeTypeReferenceExpression(typeof(string)), "Empty"))); authenticationTypeProperty.PrivateImplementationType = identityInterfaceTypeReference; entityTypeDeclaration.Members.Add(authenticationTypeProperty); //// //// public bool IsAuthenticated //// CodeMemberProperty isAuthenticatedProperty = new CodeMemberProperty() { Attributes = MemberAttributes.Public | MemberAttributes.Final, HasGet = true, Name = "IsAuthenticated", Type = new CodeTypeReference(typeof(bool)) }; // get { return (true != string.IsNullOrEmpty(this.Name)); } isAuthenticatedProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeBinaryOperatorExpression( new CodePrimitiveExpression(true), CodeBinaryOperatorType.IdentityInequality, new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(typeof(string)), "IsNullOrEmpty", new CodePropertyReferenceExpression( new CodeThisReferenceExpression(), "Name"))))); isAuthenticatedProperty.Comments.AddRange( AuthenticationCodeProcessor.GetDocComments(Resources.ApplicationServices_CommentIsAuth)); isAuthenticatedProperty.ImplementationTypes.Add(identityInterfaceTypeReference); entityTypeDeclaration.Members.Add(isAuthenticatedProperty); //// //// private string IIdentity.Name //// // VB Codegen requires us to implement a ReadOnly version of Name as well CodeMemberProperty namePropertyExp = new CodeMemberProperty() { Attributes = MemberAttributes.Private | MemberAttributes.Final, HasGet = true, Name = "Name", Type = new CodeTypeReference(typeof(string)) }; // get { return this.Name; } namePropertyExp.GetStatements.Add( new CodeMethodReturnStatement( new CodePropertyReferenceExpression( new CodeThisReferenceExpression(), "Name"))); namePropertyExp.PrivateImplementationType = identityInterfaceTypeReference; entityTypeDeclaration.Members.Add(namePropertyExp); //// //// private IIdentity IPrincipal.Identity //// CodeMemberProperty identityProperty = new CodeMemberProperty() { Attributes = MemberAttributes.Private | MemberAttributes.Final, HasGet = true, Name = "Identity", Type = identityInterfaceTypeReference, }; // get { return this; } identityProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeThisReferenceExpression())); identityProperty.PrivateImplementationType = principalInterfaceTypeReference; entityTypeDeclaration.Members.Add(identityProperty); //// //// public bool IsInRole(string role) //// CodeMemberMethod isInRoleMethod = new CodeMemberMethod() { Attributes = MemberAttributes.Public | MemberAttributes.Final, Name = "IsInRole", ReturnType = new CodeTypeReference(typeof(bool)) }; isInRoleMethod.Parameters.Add( new CodeParameterDeclarationExpression( new CodeTypeReference(typeof(string)), "role")); // if (this.Roles == null) // { // return false; // } // return this.Roles.Contains(role); CodeConditionStatement ifRolesNullStatement = new CodeConditionStatement(); ifRolesNullStatement.Condition = new CodeBinaryOperatorExpression( new CodePropertyReferenceExpression( new CodeThisReferenceExpression(), "Roles"), CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null)); ifRolesNullStatement.TrueStatements.Add( new CodeMethodReturnStatement(new CodePrimitiveExpression(false))); isInRoleMethod.Statements.Add(ifRolesNullStatement); isInRoleMethod.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeTypeReferenceExpression( new CodeTypeReference(typeof(Enumerable)) { Options = CodeTypeReferenceOptions.GlobalReference }), "Contains", new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Roles"), new CodeVariableReferenceExpression("role")))); isInRoleMethod.Comments.AddRange( AuthenticationCodeProcessor.GetDocComments(Resources.ApplicationServices_CommentIsInRole)); isInRoleMethod.ImplementationTypes.Add(principalInterfaceTypeReference); entityTypeDeclaration.Members.Add(isInRoleMethod); // Changes to Name need to raise change notification for IsAuthenticated. To accomplish this, // we'll insert a change event at the end of the "if (this._name != value)" block. // // >> this.RaisePropertyChanged("IsAuthenticated"); CodeMemberProperty nameProperty = entityTypeDeclaration.Members.OfType <CodeMemberProperty>().Where(c => c.Name == "Name").First(); nameProperty.SetStatements.OfType <CodeConditionStatement>().First().TrueStatements.Add( new CodeExpressionStatement( new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "RaisePropertyChanged", new CodePrimitiveExpression("IsAuthenticated")))); // Name should be set to string.Empty by default CodeMemberField nameField = entityTypeDeclaration.Members.OfType <CodeMemberField>().Where(c => c.Name == "_name").Single(); nameField.InitExpression = new CodePropertyReferenceExpression( new CodeTypeReferenceExpression(typeof(string)), "Empty"); } // Set context base type CodeTypeDeclaration providerTypeDeclaration; typeMapping.TryGetValue(domainServiceDescription.DomainServiceType, out providerTypeDeclaration); if (providerTypeDeclaration != null) { providerTypeDeclaration.BaseTypes.Clear(); providerTypeDeclaration.BaseTypes.Add( new CodeTypeReference(AuthenticationCodeProcessor.AuthenticationDomainContextBaseName) { Options = CodeTypeReferenceOptions.GlobalReference }); } }