/// <summary>
 /// Initializes a new instance of the <see cref="CustomMethodProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="proxyClass">Entity <see cref="CodeTypeDeclaration"/> into which to generate code</param>
 /// <param name="entityType">The type of the entity.  Cannot be null.</param>
 /// <param name="domainServiceDescriptions">Collection of all <see cref="DomainServiceDescription"/>s defined in this project</param>
 /// <param name="notificationMethodGen">Code generator for OnMethodName() methods</param>
 public CustomMethodProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration proxyClass, Type entityType, ICollection<DomainServiceDescription> domainServiceDescriptions, NotificationMethodGenerator notificationMethodGen)
     : base(proxyGenerator)
 {
     this._entityType = entityType;
     this._proxyClass = proxyClass;
     this._domainServiceDescriptions = domainServiceDescriptions;
     this._notificationMethodGen = notificationMethodGen;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="CustomMethodProxyGenerator"/> class.
 /// </summary>
 /// <param name="proxyGenerator">The client proxy generator against which this will generate code.  Cannot be null.</param>
 /// <param name="proxyClass">Entity <see cref="CodeTypeDeclaration"/> into which to generate code</param>
 /// <param name="entityType">The type of the entity.  Cannot be null.</param>
 /// <param name="domainServiceDescriptions">Collection of all <see cref="DomainServiceDescription"/>s defined in this project</param>
 /// <param name="notificationMethodGen">Code generator for OnMethodName() methods</param>
 public CustomMethodProxyGenerator(CodeDomClientCodeGenerator proxyGenerator, CodeTypeDeclaration proxyClass, Type entityType, ICollection <DomainServiceDescription> domainServiceDescriptions, NotificationMethodGenerator notificationMethodGen)
     : base(proxyGenerator)
 {
     this._entityType = entityType;
     this._proxyClass = proxyClass;
     this._domainServiceDescriptions = domainServiceDescriptions;
     this._notificationMethodGen     = notificationMethodGen;
 }
        /// <summary>
        /// Generates the client proxy code for a domain service.
        /// </summary>
        public override void Generate()
        {
            // ----------------------------------------------------------------
            // Namespace
            // ----------------------------------------------------------------
            Type                domainServiceType = this._domainServiceDescription.DomainServiceType;
            CodeNamespace       ns         = this.ClientProxyGenerator.GetOrGenNamespace(domainServiceType);
            AttributeCollection attributes = this._domainServiceDescription.Attributes;

            // Missing namespace bails out of code-gen -- error has been logged
            if (ns == null)
            {
                return;
            }

            // ----------------------------------------------------------------
            // public partial sealed class {Name} : DomainContext
            // ----------------------------------------------------------------
            string clientTypeName = DomainContextTypeName(this._domainServiceDescription);

            CodeTypeDeclaration proxyClass = CodeGenUtilities.CreateTypeDeclaration(clientTypeName, domainServiceType.Namespace);

            proxyClass.IsPartial      = true;
            proxyClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
            ns.Types.Add(proxyClass);

            CodeTypeReference domainContextTypeName = CodeGenUtilities.GetTypeReference(TypeConstants.DomainContextTypeFullName, ns.Name, false);

            proxyClass.BaseTypes.Add(domainContextTypeName);

            // Add <summary> xml comment to class
            string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_DomainContext_Class_Summary_Comment, domainServiceType.Name);

            proxyClass.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp));

            // ----------------------------------------------------------------
            // [DomainIdentifier], etc attributes move through metadata pipeline
            // ----------------------------------------------------------------
            CustomAttributeGenerator.GenerateCustomAttributes(
                this.ClientProxyGenerator,
                proxyClass,
                ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeType, ex.Message, proxyClass.Name, ex.InnerException.Message),
                attributes.Cast <Attribute>(),
                proxyClass.CustomAttributes,
                proxyClass.Comments);

            // ----------------------------------------------------------------
            // Add default OnCreated partial method
            // ----------------------------------------------------------------
            NotificationMethodGenerator notificationMethodGen = new NotificationMethodGenerator(this.ClientProxyGenerator);

            proxyClass.Members.AddRange(notificationMethodGen.PartialMethodsSnippetBlock);

            // ----------------------------------------------------------------
            // Generate a contract interface for the service.
            // ----------------------------------------------------------------
            CodeTypeDeclaration contractInterface = this.GenerateContract(proxyClass);

            // ----------------------------------------------------------------
            // Generate constructors
            // ----------------------------------------------------------------
            EnableClientAccessAttribute enableClientAccessAttribute = attributes.OfType <EnableClientAccessAttribute>().Single();

            this.GenerateConstructors(proxyClass, contractInterface, enableClientAccessAttribute, notificationMethodGen.OnCreatedMethodInvokeExpression);

            // ----------------------------------------------------------------
            // Separate proxies for each domain operation entry
            // ----------------------------------------------------------------
            DomainOperationEntryProxyGenerator methodProxyGenerator = new DomainOperationEntryProxyGenerator(this.ClientProxyGenerator, proxyClass, this._domainServiceDescription);

            methodProxyGenerator.Generate();

            // ----------------------------------------------------------------
            // Invoke operations
            // ----------------------------------------------------------------
            InvokeOperationProxyGenerator invokeOperationProxyGenerator = new InvokeOperationProxyGenerator(this.ClientProxyGenerator, proxyClass, this._domainServiceDescription);

            invokeOperationProxyGenerator.Generate();

            // ----------------------------------------------------------------
            // EntityContainer instantiation
            // ----------------------------------------------------------------

            // The entity container holds a collection of EntityLists, one per visible entity root type.
            // The derived entity types are stored in their respective root's list and do not get their own.
            this.GenEntityContainer(proxyClass, this._domainServiceDescription.RootEntityTypes, this._domainServiceDescription);

            // Register created CodeTypeDeclaration with mapping
            this._typeMapping[domainServiceType] = proxyClass;
        }
        public override void Generate()
        {
            // ----------------------------------------------------------------
            // namespace
            // ----------------------------------------------------------------
            CodeNamespace ns = this.ClientProxyGenerator.GetOrGenNamespace(this.ClientProxyGenerator.ClientProxyCodeGenerationOptions.ClientRootNamespace);

            // Missing namespace bails out of code-gen -- error has been logged
            if (ns == null)
            {
                return;
            }

            // Log an informational message to help users see progress
            this.ClientProxyGenerator.LogMessage(Resource.CodeGen_Generating_WebContext);

            // Find the AuthenticationServices and if there's just one, use it as the default.
            IEnumerable<DomainServiceDescription> authDescriptions =
                this.ClientProxyGenerator.DomainServiceDescriptions.Where(d => typeof(IAuthentication<>).DefinitionIsAssignableFrom(d.DomainServiceType));
            DomainServiceDescription defaultAuthDescription = null;
            if (authDescriptions.Count() > 1)
            {
                this.ClientProxyGenerator.LogMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        Resource.WebContext_ManyAuthServices,
                        string.Join(",", authDescriptions.Select(d => d.DomainServiceType.Name).ToArray())));
            }
            else
            {
                defaultAuthDescription = authDescriptions.FirstOrDefault();
            }

            // ----------------------------------------------------------------
            // public partial sealed class WebContext : WebContextBase
            // ----------------------------------------------------------------
            CodeTypeDeclaration proxyClass = CodeGenUtilities.CreateTypeDeclaration("WebContext", ns.Name);

            proxyClass.IsPartial = true;
            proxyClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
            proxyClass.BaseTypes.Add(CodeGenUtilities.GetTypeReference(TypeConstants.WebContextBaseName, ns.Name, false));
            proxyClass.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentClass, this.ClientProxyGenerator.IsCSharp));

            ns.Types.Add(proxyClass);

            // ----------------------------------------------------------------
            // public WebContext()
            // {
            //     <!-- if there's a default authentication service
            //     this.Authentication = new WebUserService();
            //     -->
            //     this.OnCreated();
            // }
            // ----------------------------------------------------------------
            CodeConstructor constructor = new CodeConstructor();

            constructor.Attributes = MemberAttributes.Public;
            //if (defaultAuthDescription != null)
            //{
            //    // TODO: Choose between Forms and Windows when reading from web.config is available
            //    //constructor.Statements.Add(
            //    //    new CodeAssignStatement(
            //    //        new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Authentication"),
            //    //        new CodeObjectCreateExpression(WebContextGenerator.FormsAuthenticationName)));
            //}
            NotificationMethodGenerator onCreatedMethodGenerator = new NotificationMethodGenerator(
                this.ClientProxyGenerator,
                this.ClientProxyGenerator.IsCSharp ? IndentationLevel.Namespace : IndentationLevel.GlobalNamespace);
            constructor.Statements.Add(onCreatedMethodGenerator.OnCreatedMethodInvokeExpression);
            constructor.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentConstructor, this.ClientProxyGenerator.IsCSharp));

            proxyClass.Members.Add(constructor);

            // ----------------------------------------------------------------
            // #region Extensibility Method Definitions
            // partial void OnCreated();
            // #endregion
            // ----------------------------------------------------------------
            proxyClass.Members.AddRange(onCreatedMethodGenerator.PartialMethodsSnippetBlock);

            // ----------------------------------------------------------------
            // public static new WebContext Current
            // {
            //     get { return (WebContext)WebContextBase.Current; }
            // }
            // ----------------------------------------------------------------
            CodeMemberProperty currentProperty = new CodeMemberProperty();
            string typeFullName = (string.IsNullOrEmpty(ns.Name) ? string.Empty : ns.Name + ".") + "WebContext";
            CodeTypeReference targetTypeRef = CodeGenUtilities.GetTypeReference(typeFullName, ns.Name, true);
            CodeTypeReference baseTypeRef = CodeGenUtilities.GetTypeReference(TypeConstants.WebContextBaseName, ns.Name, false);
            CodeTypeReferenceExpression baseTypeRefExp = new CodeTypeReferenceExpression(baseTypeRef);

            currentProperty.Attributes = MemberAttributes.Public | MemberAttributes.Static | MemberAttributes.New;
            currentProperty.Type = targetTypeRef;
            currentProperty.Name = "Current";
            currentProperty.HasGet = true;
            currentProperty.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeCastExpression(currentProperty.Type,
                        new CodePropertyReferenceExpression(baseTypeRefExp, "Current"))));
            currentProperty.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentCurrent, this.ClientProxyGenerator.IsCSharp));

            proxyClass.Members.Add(currentProperty);

            // ----------------------------------------------------------------
            // <!-- if there's a default authentication service
            // public new MyUser User
            // {
            //     get { return (MyUser)base.User; }
            // }
            // -->
            // ----------------------------------------------------------------
            if (defaultAuthDescription != null)
            {
                Type genericType = null;
                typeof(IAuthentication<>).DefinitionIsAssignableFrom(defaultAuthDescription.DomainServiceType, out genericType);
                if ((genericType != null) && (genericType.GetGenericArguments().Count() == 1))
                {
                    CodeMemberProperty userProperty = new CodeMemberProperty();

                    userProperty.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final;
                    userProperty.Type = CodeGenUtilities.GetTypeReference(
                        genericType.GetGenericArguments()[0], this.ClientProxyGenerator, proxyClass);
                    userProperty.Name = "User";
                    userProperty.HasGet = true;
                    userProperty.GetStatements.Add(
                        new CodeMethodReturnStatement(
                            new CodeCastExpression(userProperty.Type,
                                new CodePropertyReferenceExpression(
                                    new CodeBaseReferenceExpression(),
                                    "User"))));
                    userProperty.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentUser, this.ClientProxyGenerator.IsCSharp));

                    proxyClass.Members.Add(userProperty);
                }
            }
        }
Example #5
0
        public override void Generate()
        {
            // ----------------------------------------------------------------
            // namespace
            // ----------------------------------------------------------------
            CodeNamespace ns = this.ClientProxyGenerator.GetOrGenNamespace(this.ClientProxyGenerator.ClientProxyCodeGenerationOptions.ClientRootNamespace);

            // Missing namespace bails out of code-gen -- error has been logged
            if (ns == null)
            {
                return;
            }

            // Log an informational message to help users see progress
            this.ClientProxyGenerator.LogMessage(Resource.CodeGen_Generating_WebContext);

            // Find the AuthenticationServices and if there's just one, use it as the default.
            IEnumerable <DomainServiceDescription> authDescriptions =
                this.ClientProxyGenerator.DomainServiceDescriptions.Where(d => typeof(IAuthentication <>).DefinitionIsAssignableFrom(d.DomainServiceType));
            DomainServiceDescription defaultAuthDescription = null;

            if (authDescriptions.Count() > 1)
            {
                this.ClientProxyGenerator.LogMessage(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        Resource.WebContext_ManyAuthServices,
                        string.Join(",", authDescriptions.Select(d => d.DomainServiceType.Name).ToArray())));
            }
            else
            {
                defaultAuthDescription = authDescriptions.FirstOrDefault();
            }

            // ----------------------------------------------------------------
            // public partial sealed class WebContext : WebContextBase
            // ----------------------------------------------------------------
            CodeTypeDeclaration proxyClass = CodeGenUtilities.CreateTypeDeclaration("WebContext", ns.Name);

            proxyClass.IsPartial      = true;
            proxyClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
            proxyClass.BaseTypes.Add(CodeGenUtilities.GetTypeReference(TypeConstants.WebContextBaseName, ns.Name, false));
            proxyClass.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentClass, this.ClientProxyGenerator.IsCSharp));

            ns.Types.Add(proxyClass);

            // ----------------------------------------------------------------
            // public WebContext()
            // {
            //     <!-- if there's a default authentication service
            //     this.Authentication = new WebUserService();
            //     -->
            //     this.OnCreated();
            // }
            // ----------------------------------------------------------------
            CodeConstructor constructor = new CodeConstructor();

            constructor.Attributes = MemberAttributes.Public;
            //if (defaultAuthDescription != null)
            //{
            //    // TODO: Choose between Forms and Windows when reading from web.config is available
            //    //constructor.Statements.Add(
            //    //    new CodeAssignStatement(
            //    //        new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Authentication"),
            //    //        new CodeObjectCreateExpression(WebContextGenerator.FormsAuthenticationName)));
            //}
            NotificationMethodGenerator onCreatedMethodGenerator = new NotificationMethodGenerator(
                this.ClientProxyGenerator,
                this.ClientProxyGenerator.IsCSharp ? IndentationLevel.Namespace : IndentationLevel.GlobalNamespace);

            constructor.Statements.Add(onCreatedMethodGenerator.OnCreatedMethodInvokeExpression);
            constructor.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentConstructor, this.ClientProxyGenerator.IsCSharp));

            proxyClass.Members.Add(constructor);

            // ----------------------------------------------------------------
            // #region Extensibility Method Definitions
            // partial void OnCreated();
            // #endregion
            // ----------------------------------------------------------------
            proxyClass.Members.AddRange(onCreatedMethodGenerator.PartialMethodsSnippetBlock);

            // ----------------------------------------------------------------
            // public static new WebContext Current
            // {
            //     get { return (WebContext)WebContextBase.Current; }
            // }
            // ----------------------------------------------------------------
            CodeMemberProperty          currentProperty = new CodeMemberProperty();
            string                      typeFullName    = (string.IsNullOrEmpty(ns.Name) ? string.Empty : ns.Name + ".") + "WebContext";
            CodeTypeReference           targetTypeRef   = CodeGenUtilities.GetTypeReference(typeFullName, ns.Name, true);
            CodeTypeReference           baseTypeRef     = CodeGenUtilities.GetTypeReference(TypeConstants.WebContextBaseName, ns.Name, false);
            CodeTypeReferenceExpression baseTypeRefExp  = new CodeTypeReferenceExpression(baseTypeRef);

            currentProperty.Attributes = MemberAttributes.Public | MemberAttributes.Static | MemberAttributes.New;
            currentProperty.Type       = targetTypeRef;
            currentProperty.Name       = "Current";
            currentProperty.HasGet     = true;
            currentProperty.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeCastExpression(currentProperty.Type,
                                           new CodePropertyReferenceExpression(baseTypeRefExp, "Current"))));
            currentProperty.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentCurrent, this.ClientProxyGenerator.IsCSharp));

            proxyClass.Members.Add(currentProperty);

            // ----------------------------------------------------------------
            // <!-- if there's a default authentication service
            // public new MyUser User
            // {
            //     get { return (MyUser)base.User; }
            // }
            // -->
            // ----------------------------------------------------------------
            if (defaultAuthDescription != null)
            {
                Type genericType = null;
                typeof(IAuthentication <>).DefinitionIsAssignableFrom(defaultAuthDescription.DomainServiceType, out genericType);
                if ((genericType != null) && (genericType.GetGenericArguments().Count() == 1))
                {
                    CodeMemberProperty userProperty = new CodeMemberProperty();

                    userProperty.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final;
                    userProperty.Type       = CodeGenUtilities.GetTypeReference(
                        genericType.GetGenericArguments()[0], this.ClientProxyGenerator, proxyClass);
                    userProperty.Name   = "User";
                    userProperty.HasGet = true;
                    userProperty.GetStatements.Add(
                        new CodeMethodReturnStatement(
                            new CodeCastExpression(userProperty.Type,
                                                   new CodePropertyReferenceExpression(
                                                       new CodeBaseReferenceExpression(),
                                                       "User"))));
                    userProperty.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentUser, this.ClientProxyGenerator.IsCSharp));

                    proxyClass.Members.Add(userProperty);
                }
            }
        }
        /// <summary>
        /// Generates the client proxy code for a domain service.
        /// </summary>
        public override void Generate()
        {
            // ----------------------------------------------------------------
            // Namespace
            // ----------------------------------------------------------------
            Type domainServiceType = this._domainServiceDescription.DomainServiceType;
            CodeNamespace ns = this.ClientProxyGenerator.GetOrGenNamespace(domainServiceType);
            AttributeCollection attributes = this._domainServiceDescription.Attributes;

            // Missing namespace bails out of code-gen -- error has been logged
            if (ns == null)
            {
                return;
            }

            // ----------------------------------------------------------------
            // public partial sealed class {Name} : DomainContext
            // ----------------------------------------------------------------
            string clientTypeName = DomainContextTypeName(this._domainServiceDescription);

            CodeTypeDeclaration proxyClass = CodeGenUtilities.CreateTypeDeclaration(clientTypeName, domainServiceType.Namespace);
            proxyClass.IsPartial = true;
            proxyClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
            ns.Types.Add(proxyClass);

            CodeTypeReference domainContextTypeName = CodeGenUtilities.GetTypeReference(TypeConstants.DomainContextTypeFullName, ns.Name, false);
            proxyClass.BaseTypes.Add(domainContextTypeName);

            // Add <summary> xml comment to class
            string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_DomainContext_Class_Summary_Comment, domainServiceType.Name);
            proxyClass.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, this.ClientProxyGenerator.IsCSharp));

            // ----------------------------------------------------------------
            // [DomainIdentifier], etc attributes move through metadata pipeline
            // ----------------------------------------------------------------
            CustomAttributeGenerator.GenerateCustomAttributes(
                this.ClientProxyGenerator,
                proxyClass,
                ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeType, ex.Message, proxyClass.Name, ex.InnerException.Message),
                attributes.Cast<Attribute>(),
                proxyClass.CustomAttributes,
                proxyClass.Comments);

            // ----------------------------------------------------------------
            // Add default OnCreated partial method
            // ----------------------------------------------------------------
            NotificationMethodGenerator notificationMethodGen = new NotificationMethodGenerator(this.ClientProxyGenerator);
            proxyClass.Members.AddRange(notificationMethodGen.PartialMethodsSnippetBlock);

            // ----------------------------------------------------------------
            // Generate a contract interface for the service.
            // ----------------------------------------------------------------
            CodeTypeDeclaration contractInterface = this.GenerateContract(proxyClass);

            // ----------------------------------------------------------------
            // Generate constructors
            // ----------------------------------------------------------------
            EnableClientAccessAttribute enableClientAccessAttribute = attributes.OfType<EnableClientAccessAttribute>().Single();
            this.GenerateConstructors(proxyClass, contractInterface, enableClientAccessAttribute, notificationMethodGen.OnCreatedMethodInvokeExpression);

            // ----------------------------------------------------------------
            // Separate proxies for each domain operation entry
            // ----------------------------------------------------------------
            DomainOperationEntryProxyGenerator methodProxyGenerator = new DomainOperationEntryProxyGenerator(this.ClientProxyGenerator, proxyClass, this._domainServiceDescription);
            methodProxyGenerator.Generate();

            // ----------------------------------------------------------------
            // Invoke operations
            // ----------------------------------------------------------------
            InvokeOperationProxyGenerator invokeOperationProxyGenerator = new InvokeOperationProxyGenerator(this.ClientProxyGenerator, proxyClass, this._domainServiceDescription);
            invokeOperationProxyGenerator.Generate();

            // ----------------------------------------------------------------
            // EntityContainer instantiation
            // ----------------------------------------------------------------

            // The entity container holds a collection of EntityLists, one per visible entity root type.
            // The derived entity types are stored in their respective root's list and do not get their own.
            this.GenEntityContainer(proxyClass, this._domainServiceDescription.RootEntityTypes, this._domainServiceDescription);

            // Register created CodeTypeDeclaration with mapping
            this._typeMapping[domainServiceType] = proxyClass;
        }