Entity Framework Designer Extension Not loading - visual-studio-2010

I created a small extension for the EF designer that adds a new property to the property window. I did this using a vsix project (new project -> c# -> extensibility -> vsix project). When I hit F5 the experimental VS instance starts up. I create a new project, add an entity data model and add an entity. However, my break points never get hit and I don't see the property. Any ideas as to what I might be doing wrong?
public class AggregateRootValue
{
internal static XName AggregateRootElementName = XName.Get("AggregateRoot", "http://efex");
private readonly XElement _property;
private readonly PropertyExtensionContext _context;
public AggregateRootValue(XElement parent, PropertyExtensionContext context)
{
_property = parent;
_context = context;
}
[DisplayName("Aggregate Root")]
[Description("Determines if an entity is an Aggregate Root")]
[Category("Extensions")]
[DefaultValue(true)]
public string AggregateRoot
{
get
{
XElement child = _property.Element(AggregateRootElementName);
return (child == null) ? bool.TrueString : child.Value;
}
set
{
using (EntityDesignerChangeScope scope = _context.CreateChangeScope("Set AggregateRoot"))
{
var element = _property.Element(AggregateRootElementName);
if (element == null)
_property.Add(new XElement(AggregateRootElementName, value));
else
element.SetValue(value);
scope.Complete();
}
}
}
}
[Export(typeof(IEntityDesignerExtendedProperty))]
[EntityDesignerExtendedProperty(EntityDesignerSelection.ConceptualModelEntityType)]
public class AggregateRootFactory : IEntityDesignerExtendedProperty
{
public object CreateProperty(XElement element, PropertyExtensionContext context)
{
var edmXName = XName.Get("Key", "http://schemas.microsoft.com/ado/2008/09/edm");
var keys = element.Parent.Element(edmXName).Elements().Select(e => e.Attribute("Name").Value);
if (keys.Contains(element.Attribute("Name").Value))
return new AggregateRootValue(element, context);
return null;
}
}
EDIT: I put the code on Github: https://github.com/devlife/Sandbox
EDIT: After Adding the MEF component to the manifest as suggested, the extension still never loads. Here is a picture of the manifest:

So the answer, as it turns out, is in how I setup my project. I put both classes inside the project which produces the VSIX file. By simply moving those classes into another project and setting that project as the MEF Component in the manifest (and thus copying the assembly) it worked like a charm!

For VS2012, it is only needed to add Solution as MEF component also. Just add whole solution as MEF component also.
Then it works surprisingly fine.

It seems the dll built by your project isn't automatically included in the generated VSIX package, and VS2013 doesn't give you options through the IDE to change this (that I can work out, anyway).
You have to manually open the project file and alter the XML. The property to change is IncludeAssemblyInVSIXContainer.
Seen here: How to include VSIX output in it's package?

Related

How to a raise a domain event for the entity when the entity is created in clean architecture

I have a project created using the clean architecture template.
If I want a domain event be raised when a new project is created, where do I add that?
If I have to raise an event whenever a new item be added to a project, I can accomplish that in the Project entity as shown here.
Similarly for MarkCompletion of a ToDoItem as done here.
But its not clear where do I put the code to raise an event when a new Project is created?
One option is doing something like the following in Create End Point here.
newProject.Events.Add(new ProjectCreatedEvent(newProject));
But this is in UI, away from the domain model, and so does not feel right.
The other option is using ef core interceptors. So when ever save changes is called, just raise event as appropriate something like here.
And if I add event in Project ctor, then this is triggered even in case of an update.
public Project(string name)
{
Name = Guard.Against.NullOrEmpty(name, nameof(name));
var newProjectCreatedEvent = new NewProjectCreatedEvent(this);
Events.Add(newProjectCreatedEvent);
}
Are there any better options/patterns?
Any pointer is deeply appreciated.
When you need to raise a domain event on project creation I would create a factory method that publishes the event.
You can use a static method or implement a factory object.
public class Project : BaseEntity, IAggregateRoot
{
public static Project newProject(string name)
{
var project = new Project(name);
var newProjectCreatedEvent = new NewProjectCreatedEvent(project);
Events.Add(newProjectCreatedEvent);
return project;
}
private Project(string name)
{
Name = Guard.Against.NullOrEmpty(name, nameof(name));
}
}

Getting "main" Assembly version number

I have a solution with libraries (DLLs) which are used in 2 identical projects (one for WP7, another for WP8). In one of the libraries I have the code which determines the version of the application.
private static Version mVersion;
public static Version Version {
get {
if (mVersion == default(Version)) {
var lcAssembly = Assembly.GetExecutingAssembly();
var parts = lcAssembly.FullName.Split(',');
var lcVersionStr = parts[1].Split('=')[1];
mVersion = new Version(lcVersionStr);
}
return mVersion;
}
}
The problem is that this code returns the version number of the library itself because of this Assembly.GetExecutingAssembly() code. How to get a MAIN Assembly version and not DLL's?
That's a great question on code-sharing between WP7 and WP8.
The simplest way for you to do that would be to read the AppManfiest.xml file at run-time, get the EntryType and use that to get at the entry point Assembly instance. Here's how a sample AppManfiest.xml looks like once MSBuild did its magic on it:
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="myAssembly" EntryPointType="myNamespace.App" RuntimeVersion="4.7.50308.0">
<Deployment.Parts>
<AssemblyPart x:Name="myAssembly" Source="myAssembly.dll" />
</Deployment.Parts>
</Deployment>
And here's how you would read the file, get the attributes, then get the entry point type and finally the entry point assembly:
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var appManfiest = XElement.Load("AppManifest.xaml");
var entryAssemblyName = appManfiest.Attribute("EntryPointAssembly").Value;
var entryTypeName = appManfiest.Attribute("EntryPointType").Value;
Type entryType = Type.GetType(entryTypeName + "," + entryAssemblyName);
Assembly entryAssembly = entryType.Assembly;
}
That's a simple solution and it works. However, that isn't the cleanest architectural solution. The way I'd implement this solution is to have an interface declared in the shared library, both WP7 and WP8 implement that interface and register their implementation with an IoC container.
For example, let's say you need to "DoSomething" in the shared library that's platform version specific. First you'll create have an IDoSomething interface. Let's also assume you have an IoC standing by.
public interface IDoSomething
{
}
public static class IoC
{
public static void Register<T>(T t)
{
// use some IoC container
}
public static T Get<T>()
{
// use some IoC container
}
}
In your WP7 app you'll implement the shared Interface for WP7 and register it once the WP7 starts up.
public App()
{
MainPage.IoC.Register(new MainPage.DoSomethingWP7());
}
private class DoSomethingWP7 : IDoSomething
{
}
You'll also do the same for WP8 in the WP8 app. And in your shared library you can then ask for the relevant interface regardless of its platform version specific implementation:
IDoSomething sharedInterface = IoC.Get<IDoSomething>();
I have a simpler answer. I think you are close with what you are doing. I just used your code with one modification so I can use it with the Telerik controls. Here's what I did. I located your code in my project's App class (codebehind of App.Xaml). I made one change that I think will take care of your problem:
private static Version mVersion;
public static Version Version {
get {
if (mVersion == default(Version)) {
var lcAssembly = typeof(App);
var parts = lcAssembly.FullName.Split(',');
var lcVersionStr = parts[1].Split('=')[1];
mVersion = new Version(lcVersionStr);
}
return mVersion;
}
}
Now I can get the version number by calling "App.Version".
This worked for me:
var appAssembly = Application.Current.GetType().Assembly;
var appAssemblyVersion = appAssembly.GetName().Version;
I tested with WP7.1 and WP8.0.

Adding a custom editor to visual studio editor list

I am in the process of writing a custom editor for visual studio. I have implemented some basic functionality for the new language e.g. syntax highlighting and I succesfully installed tha package by using the generated .vsix file. All works just nice, however my custom editor needs to be able to be associated with different file extensions.
I thought, mistakenly, that since I installed the editor it would appear under
Tools->Options..->Text Editor->File Extension->Editors list:
However it does not appear there. So the question is: how do you add a custom editor to this list?
Thanks for any help!
Well at least I got the tumbleweed badge for this question.
After a lot of reverse engineering I found the solution... which is not documented.. Anywhere..
Step number 1:
First you need to create an editor factory with all the bells and whistles it comes with - MSVS has an extension for it.
Step number 2:
Then you have to create such a class
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
class ProvideFileExtensionMapping : RegistrationAttribute
{
private readonly string _name, _id, _editorGuid, _package;
private readonly int _sortPriority;
public ProvideFileExtensionMapping(string id, string name, object editorGuid, string package, int sortPriority)
{
_id = id;
_name = name;
if (editorGuid is Type)
{
_editorGuid = ((Type)editorGuid).GUID.ToString("B");
}
else
{
_editorGuid = editorGuid.ToString();
}
_package = package;
_sortPriority = sortPriority;
}
public override void Register(RegistrationContext context)
{
using (Key mappingKey = context.CreateKey("FileExtensionMapping\\" + _id))
{
mappingKey.SetValue("", _name);
mappingKey.SetValue("DisplayName", _name);
mappingKey.SetValue("EditorGuid", _editorGuid);
mappingKey.SetValue("Package", _package);
mappingKey.SetValue("SortPriority", _sortPriority);
}
}
public override void Unregister(RegistrationAttribute.RegistrationContext context)
{
}
}
Step 3:
Then you need to add this class as an attribute to your editor factory (which you created in step 1):
[ProvideFileExtensionMapping("{E23E32ED-3467-4401-A364-1352666A3502}", "RText Editor", typeof(EditorFactory), GuidList.guidRTextEditorPluginEditorFactoryString, 100)]
public sealed class EditorFactory : IVsEditorFactory, IDisposable{...}
That's it. You should now be able to see your editor in the list of editors in visual studio.
Your editor shall be invoked when the file mapping is right.
Hopefully this post saves a lot of time for someone else..

Getting the current project directory from experimental instance of visual studio 2010?

I'm currently implementing uml validation http://msdn.microsoft.com/en-us/library/ee329482.aspx,
when i debug, it opens a new experimental instance of visual studio for me to validate uml diagrams.
Is there a way to get the path of project directory selected by the user when the experimental instance of visual studio is running??
To be more clear,
project A - has VSIX and Class library components to validate uml validation. These class Library components are added to VSIX as MEF components
when i debug Project A -> new experimental instance of VS will open-> Then creating a new project (ctrl+shift+N)-> select modelling project-> browse to the directory (to store the modelling project)->Name the Project as "MYMODEL" -> then press OK
Now, In my Project A i need the path of MYMODEL. Can you please tell me how do i get that path??
Thanks in Advance,
This is a bit roundabout, but works.
You need references to EnvDTE and Microsoft.VisualStudio.Shell.Immutable.10.0 as well as the usual bits.
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
namespace Validation
{
public class MyValidationExtensions
{
[Import]
public Microsoft.VisualStudio.Shell.SVsServiceProvider ServiceProvider { get; set; }
[Export(typeof(System.Action<ValidationContext, object>))]
[ValidationMethod(
ValidationCategories.Open
| ValidationCategories.Menu)]
public void ValidateClassNames
(ValidationContext context,
// This type determines what elements
// will be validated by this method:
IModel elementToValidate)
{
IModelStore store = elementToValidate.GetModelStore();
EnvDTE.DTE dte = ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
//dynamic projects = dte.ActiveSolutionProjects;
foreach (EnvDTE.Project project in dte.Solution.Projects)
{
IModelingProject mp = project as IModelingProject;
if (mp.Store == store)
{
System.Windows.Forms.MessageBox.Show(project.FullName);
}
}
}
// Add more validation methods for different element types.
}
}

How to encapsulate User Setting (Options Page) in Visual Studio 2010 AddIn

I'm currently developping a Visual Studio Extension and I have a question about Options Page. Options Page allows user to save setting about your Extension. Visual Studio handle a lot of work for us.
I created the Options Page.
public class VisualStudioParameter : DialogPage
{
private string _tfsServerUrl = DefaultParameter.TfsServerUrl;
[Category("TFS Parameters")]
[DisplayName(#"Server Name")]
[Description("The URL of your TFS Server")]
public string TfsServerUrl
{
get { return _tfsServerUrl; }
set { _tfsServerUrl = value; }
}
}
First, I created a method in the Visual Studio Package to acces to the Options Page.
Okay so now, from my Package, I can easily acces to the settings.
partial class SpecFlowTfsLinkerExtensionPackage : Package : IParameter
{
....
....
public string GetTfsServerUrl()
{
return ((VisualStudioParameter) GetDialogPage(typeof (VisualStudioParameter))).TfsServerUrl;
}
}
Now, I want to be able, in another library (Another project, included in the VSIX Package), to get easily these values. I don't want to reference the Visual Studio AddIn Package in my library.
I also have Unit Test so I'm going to create an Interface. During Unit Test, I going to Mock the object.
public interface IParameter
{
string GetTfsServerUrl();
}
Do you have any idea about how I can develop a clean solution to get these parameters from another assembly ?
Do you think the better solution is to inject the AddIn dependency in my library ?
If you already developed a Visual Studio Extension, How did you encapsulated the user setting from your core assembly ?
Thanks a lot.
You can try something like that:
// Access DTE infrastructure
EnvDTE.DTE dte = Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
// Access options page
var props = dte.get_Properties(#"Your Extension", "General");
var pathProperty = props.Item("TfsServerUrl");
path = pathProperty.Value as string;

Resources