/// <summary> /// Generates the business logic class type. We override this to control the base class and imports /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="codeNamespace">The namespace into which to generate code.</param> /// <param name="className">The name to use for the class.</param> /// <returns>The new type</returns> protected override CodeTypeDeclaration CreateBusinessLogicClass(ICodeGenContext codeGenContext, CodeNamespace codeNamespace, string className) { // Add an import for our domain service foreach (string import in BusinessLogicClassConstants.LinqToEntitiesDbImports) { codeNamespace.Imports.Add(new CodeNamespaceImport(import)); } // Add an import for the namespace of the DomainContext if (this.ContextType.Namespace != codeNamespace.Name) { codeNamespace.Imports.Add(new CodeNamespaceImport(BusinessLogicClassConstants.DbContextNamespace)); codeNamespace.Imports.Add(new CodeNamespaceImport(this.ContextType.Namespace)); } // Add to the set of known references codeGenContext.AddReference(typeof(EntityState).Assembly.FullName); // We used to add OpenRiaServices.DomainServices.EntityFramework, but due to // vstfdevdiv/DevDiv2 Bug 442272 - Domain Service Wizard failing when an EF DbContext is selected, // we need to avoid doing that. if (DbContextUtilities.DbContextTypeReference != null) { codeGenContext.AddReference(DbContextUtilities.DbContextTypeReference.Assembly.FullName); } CodeTypeDeclaration businessLogicClass = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name); CodeTypeReference baseClass = new CodeTypeReference(BusinessLogicClassConstants.DbDomainServiceTypeName, new CodeTypeReference(this.ContextType.Name)); businessLogicClass.BaseTypes.Add(baseClass); return(businessLogicClass); }
/// <summary> /// Creates the entire business logic class in the specified namespace /// </summary> /// <param name="codeGenContext">The context into which to generate code. It cannot be null.</param> /// <param name="codeNamespace">The namespace object into which the type should be defined.</param> /// <param name="className">The name of the class. It cannot be null.</param> /// <returns>A new CodeTypeDeclaration for the generated class.</returns> protected virtual CodeTypeDeclaration CreateBusinessLogicClass(ICodeGenContext codeGenContext, CodeNamespace codeNamespace, string className) { CodeTypeDeclaration businessLogicClass = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name); businessLogicClass.BaseTypes.Add(BusinessLogicClassConstants.DomainServiceTypeName); return(businessLogicClass); }
/// <summary> /// Creates the business logic class. Overridden to add imports, base class, etc. /// </summary> /// <param name="codeGenContext">The code gen context.></param> /// <param name="codeNamespace">The namespace name.</param> /// <param name="className">The class name.</param> /// <returns>the new type</returns> protected override CodeTypeDeclaration CreateBusinessLogicClass(CodeGenContext codeGenContext, CodeNamespace codeNamespace, string className) { Debug.Assert(LinqToSqlContext.linqToSqlDomainServiceAssemblyPath != null, "Unexpected method call when LinqToSqlDomainService assembly path has not been initialized!"); if (LinqToSqlContext.linqToSqlDomainServiceAssemblyPath == null) { return(null); } // Add an import for our domain service foreach (string import in BusinessLogicClassConstants.LinqToSqlImports) { codeNamespace.Imports.Add(new CodeNamespaceImport(import)); } // Add an import for the namespace of the DomainContext if (this.ContextType.Namespace != codeNamespace.Name) { codeNamespace.Imports.Add(new CodeNamespaceImport(this.ContextType.Namespace)); } // Add to the set of known references codeGenContext.AddReference(typeof(DataContext).Assembly.FullName); codeGenContext.AddReference(LinqToSqlContext.linqToSqlDomainServiceAssemblyPath); CodeTypeDeclaration businessLogicClass = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name); CodeTypeReference baseClass = new CodeTypeReference(BusinessLogicClassConstants.LinqToSqlDomainServiceTypeName, new CodeTypeReference(this.ContextType.Name)); businessLogicClass.BaseTypes.Add(baseClass); return(businessLogicClass); }
/// <summary> /// Generates the business logic class type. We override this to control the base class and imports /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="codeNamespace">The namespace into which to generate code.</param> /// <param name="className">The name to use for the class.</param> /// <returns>The new type</returns> protected override CodeTypeDeclaration CreateBusinessLogicClass(CodeGenContext codeGenContext, CodeNamespace codeNamespace, string className) { // Add an import for our domain service foreach (string import in BusinessLogicClassConstants.LinqToEntitiesImports) { codeNamespace.Imports.Add(new CodeNamespaceImport(import)); } // Add an import for the namespace of the DomainContext if (this.ContextType.Namespace != codeNamespace.Name) { codeNamespace.Imports.Add(new CodeNamespaceImport(this.ContextType.Namespace)); } // Add to the set of known references codeGenContext.AddReference(typeof(ObjectContext).Assembly.FullName); codeGenContext.AddReference(typeof(LinqToEntitiesDomainService <>).Assembly.FullName); CodeTypeDeclaration businessLogicClass = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name); CodeTypeReference baseClass = new CodeTypeReference(BusinessLogicClassConstants.LinqToEntitiesDomainServiceTypeName, new CodeTypeReference(this.ContextType.Name)); businessLogicClass.BaseTypes.Add(baseClass); return(businessLogicClass); }
/// <summary> /// Generates the metadata class for the given object (entity or complex object) /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="optionalSuffix">If not null, optional suffix to class name and namespace</param> /// <param name="type">The type of the object for which to generate the metadata class.</param> /// <returns><c>true</c> means at least some code was generated.</returns> public bool GenerateMetadataClass(ICodeGenContext codeGenContext, string optionalSuffix, Type type) { // If already have a buddy class, bypass all this logic // Use soft dependency (string name) to avoid static dependency on DataAnnotations. // We do this because this wizard must run from the GAC, and DataAnnotations will not necessarily be in the GAC too. Type buddyClassType = TypeUtilities.GetAssociatedMetadataType(type); if (buddyClassType != null) { return(false); } string className = type.Name; string classNamespace = type.Namespace; bool addSuffix = !string.IsNullOrEmpty(optionalSuffix); if (addSuffix) { className += optionalSuffix; classNamespace += optionalSuffix; } // Every object could have a unique namespace (odd, but true) // So we logically create a new namespace for each object. Those // sharing a namespace will reuse the CodeNamespace. // We allow the caller to specify in case it needs to override that // namespace. Unit testing is such a scenario CodeNamespace codeNamespace = codeGenContext.GetOrGenNamespace(classNamespace); // If we redirected to a different namespace than the object, import the real object's namespace if (addSuffix) { CodeGenUtilities.AddImportIfNeeded(codeNamespace, type.Namespace); } // Name of buddy class is $objectClassName$Metadata (e.g. Orders --> OrdersMetadata) string buddyClassName = className + "Metadata"; // We use the full outer.inner type naming convention for VB because they cannot resolve it otherwise. // C# can currently resolve it due to a bug in the compiler, but it is safer to use the legal syntax here. string fullBuddyClassName = className + "." + buddyClassName; CodeTypeDeclaration objectClass = null; // public class $objectType$ { } objectClass = CodeGenUtilities.CreateTypeDeclaration(className, classNamespace); objectClass.IsPartial = true; objectClass.TypeAttributes = TypeAttributes.Public; // Add explanatory comments about what the [MetadataTypeAttribute] does objectClass.Comments.Add(new CodeCommentStatement(String.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Entity_Partial_Class_Remarks, buddyClassName, className), false)); // [MetadataType(typeof($objectType$.$objectType$_Metadata))] CodeAttributeDeclaration attr = CodeGenUtilities.CreateAttributeDeclaration(BusinessLogicClassConstants.MetadataTypeAttributeTypeName); CodeAttributeArgument attrArg = new CodeAttributeArgument(new CodeTypeOfExpression(fullBuddyClassName)); attr.Arguments.Add(attrArg); objectClass.CustomAttributes.Add(attr); // public sealed class $objectType$_Metadata { } // (note: cannot set 'static' modified from CodeDom.) CodeTypeDeclaration buddyClass = CodeGenUtilities.CreateTypeDeclaration(buddyClassName, classNamespace); // Both VB and C# use a friend/public buddy class. A private buddy class does not // compile in VB, and it compiles in C# only due to a bug. buddyClass.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.NestedAssembly; bool generatedProperty = false; // Generate a developer comment describing what this class does buddyClass.Comments.Add(new CodeCommentStatement(String.Format(CultureInfo.CurrentCulture, Resources.Buddy_Class_Remarks, type.Name))); // Add a language-specific example string explanation = codeGenContext.IsCSharp ? Resources.Buddy_Class_Remarks_CSharp : Resources.Buddy_Class_Remarks_VB; buddyClass.Comments.Add(new CodeCommentStatement(explanation, false)); // Generate a private ctor to make it impossible to instantiate this class CodeConstructor ctor = new CodeConstructor(); ctor.Attributes = MemberAttributes.Private; ctor.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_Private_Ctor_Comment)); buddyClass.Members.Add(ctor); // Sort by name order for baseline predictability foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).OrderBy(p => p.Name)) { // CodeDom does not support auto-implemented properties, so we will generate fields and then transform them into properties Type propType = propertyInfo.PropertyType; if (propType.IsVisible && propertyInfo.GetGetMethod() != null && this.CanGeneratePropertyOfType(propType)) { // Add an import for this property type's namespace if needed CodeGenUtilities.AddImportIfNeeded(codeNamespace, propertyInfo.PropertyType.Namespace); CodeSnippetTypeMember property = CodeGenUtilities.CreateAutomaticPropertyDeclaration(codeGenContext, buddyClass, propertyInfo, !string.IsNullOrEmpty(codeNamespace.Name) /* insideNamespace */); buddyClass.Members.Add(property); generatedProperty = true; } } // Don't generate anything if the buddy class is empty if (generatedProperty) { // Add the partial object class to the namespace codeNamespace.Types.Add(objectClass); // Add the metadata class as a nested class inside the partial object class objectClass.Members.Add(buddyClass); } // false if no properties were generated, indicating no code should be emitted return(generatedProperty); }