How do I get a Roslyn workspace from a VS package? - roslyn

From a Visual Studio 2015 CTP5 package, how do I get the current Roslyn workspace?
I looked at
How to get reference to 'Roslyn' Workspace object from IVsSolution?
and
Roslyn: How to get a reference to Workspace from currently loaded solution?
but I still can't make it work:
Workspace.CurrentWorkspace does not exist anymore
I have tried importing the VisualStudioWorkspace but it is still null:
public sealed class VSPackage1Package : Package
{
....
[Import]
public VisualStudioWorkspace Workspace { get; set; }
....
protected override void Initialize()
{
// Workspace is null here...
Is there a sample somewhere?

I don't see any definition of VisualStudioWorkspace (or the Microsoft.VisualStudio.LanguageServices assembly)
It's there, double check you're looking in the right place.
[Import]s only work if the class you're working in itself is MEF exported. If it's not (like a Package in your case), just write:
var componentModel = (IComponentModel)GetService(typeof(SComponentModel));
var workspace = componentModel.GetService<VisualStudioWorkspace>();

Related

Asp.Net Core Dependency Injection doesn't work, if it is started from unmanaged/native

First i try to explain the story.
I wanted to extend an C++/MFC application with REST-APIs, and decided to use for this purpose Asp.Net-Core 5 in a library by bridging it to unmanaged code with C++/CLI library. (having a separete ASP application is doubled expenditure, and needed to be rewritten all the logic in C#. in that regard RESTful-Server should be in same process implemented.)
Asp-Host is started in that way; C++/MFC -> C++/CLI -> ASP-Library (ASP referenced in CLI, CLI referenced in Native)
First problem was; by building the host Microsoft.Extensions.Hosting.Abstractions-Assembly could not be resolved. I found that, "My CLI Library".runtimeconfig.json has wrong framework reference and causes it not to be resolved. That means generated runtimeconfig.json is wrong. After every build it has to be manually with AspNetCore instead of NETCore corrected. (Done in PostBuildEvent)
Next problem; during the ASP-Host build, ASP could not resolve "My ASP Library.dll"-Assembly (in reflection). This problem solved by OnAssemblyResolve event by giving the right path. I'm not sure whether it is correct solution. Because AppDomain.BaseDirectory is an empty string, maybe it is the cause of it, that the library could not found.
In AssemblyResolve event;
Assembly::LoadFrom(assemblyFile)
Finally i could start the server, and it works. Then needed to use dependency injection, and my service could not be resolved from the controller.
Then i used my ASP-Library in another C#-project to test and it works...
i'm sure that it doesn't work if the entry point of process is in unmanaged code.
public interface IServerImpl
{
void OnFail(String msg);
}
public class CServerImpl : IServerImpl
{
public void OnFail(String msg)
{
}
}
... in Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IServerImpl, CServerImpl>();
services.AddControllers();
}
... Controller
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private readonly IServerImpl _serverImpl;
public WeatherForecastController(ILogger<WeatherForecastController> logger, IServerImpl serverImpl)
{
_logger = logger;
_serverImpl = serverImpl;
}
...
}
Is there any workaround to have it working? Are those problems bug in Asp.Net-Core or what am i doing wrong?
Thanks in advance
The problem has been solved. Assembly resolving event with Assembly.LoadFrom() causes my ASP-assembly to be loaded (or mapped) twice. Loading it in different assembly-load-context means that, doubled Types, static variables and so on. In that regard my registered IServerImpl service searched in the controller with another IServerImpl type. Type names are identical, but not the same.
For more information see technical challenges: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext?view=net-5.0
Another issue on GitHub: https://github.com/dotnet/runtime/issues/39783
In assembly resolve event, i'm returning now the loaded assembly like that, instead of loading it again;
AppDomain.CurrentDomain.GetAssemblies()
.SingleOrDefault(asm => asm.FullName.StartsWith(args.Name.Split(',')[0] + ","))
still wellcome answers which clarifies "why my ASP-assembly not found from the framework?"

VS 2017 Designer: Method not found

I have a windows form that contains a user control (each defined in separate assemblies). Both the form and the user control call an extension method on BindingList<>. The extension method is defined in a 3rd assembly. Everything compiles & runs fine.
However, if I try to open the form in Visual Studio 2017 designer, I get an error:
To prevent possible data loss before loading the designer, the following errors must be resolved:
Method not found: 'System.ComponentModel.BindingList1 KamaTrenda.Utilities.Lists.ListUtilities.AddReset(System.ComponentModel.BindingList1,
System.Collections.Generic.IEnumerable`1)'.
Call stack:
at System.ComponentModel.ReflectPropertyDescriptor.SetValue(Object
component, Object value) at
Microsoft.VisualStudio.Shell.Design.VsTargetFrameworkPropertyDescriptor.SetValue(Object
component, Object value) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializePropertyAssignStatement(IDesignerSerializationManager
manager, CodeAssignStatement statement,
CodePropertyReferenceExpression propertyReferenceEx, Boolean
reportError) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializeAssignStatement(IDesignerSerializationManager
manager, CodeAssignStatement statement) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializeStatement(IDesignerSerializationManager
manager, CodeStatement statement)
Commenting out the content of the setter of this property allows for opening the form in the designer:
public IList<IPosition> PositionsToDisplay
{
get { return myPositionsToDisplay.Select(x => x.Position).ToList(); }
set { myPositionsToDisplay.AddReset(value.Select(x => new PositionAdapter(x))); }
}
myPositionsToDisplay:
private readonly BindingList<PositionAdapter> myPositionsToDisplay = new SortableBindingList<PositionAdapter>();
And AddReset:
public static class ListUtilities
{
public static BindingList<T> AddReset<T>(this BindingList<T> list, IEnumerable<T> toAdd)
{
list.RaiseListChangedEvents = false;
foreach (T item in toAdd)
list.Add(item);
list.RaiseListChangedEvents = true;
list.ResetBindings();
return list; // for chaining
}
}
I have tried adding
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
to the definition of PositionsToDisplay, and it made no difference.
I tried rebuilding, manually deleting the contents obj & bin directories for all 3 projects, as well as the contents of AppData\Local\Microsoft\VisualStudio\15.0_6d397e1a\ProjectAssemblies, closing all open documents in VS 2017, closing the solution, and restarting Visual Studio, and it made no difference.
The .resx file of neither the form, nor the control, refer to the property.
The Designer.cs for the form had some code that seemed to be causing the issue:
this.control.PositionsToDisplay = ((System.Collections.Generic.IList<IPosition>)(resources.GetObject("control.PositionsToDisplay")));
Deleting this (presumably after adding DesignerSerializationVisibility.Hidden, so that it does not get re-generated) seemed to solve the issue.

Sitecore: Glass Mapper Code First

It is possible to automatically generate Sitecore templates just coding models? I'm using Sitecore 8.0 and I saw Glass Mapper Code First approach but I cant find more information about that.
Not sure why there isn't much info about it, but you can definitely model/code first!. I do it alot using the attribute configuration approach like so:
[SitecoreType(true, "{generated guid}")]
public class ExampleModel
{
[SitecoreField("{generated guid}", SitecoreFieldType.SingleLineText)]
public virtual string Title { get; set; }
}
Now how this works. The SitecoreType 'true' value for the first parameter indicates it may be used for codefirst. There is a GlassCodeFirstDataprovider which has an Initialize method, executed in Sitecore's Initialize pipeline. This method will collect all configurations marked for codefirst and create it in the sql dataprovider. The sections and fields are stored in memory. It also takes inheritance into account (base templates).
I think you first need to uncomment some code in the GlassMapperScCustom class you get when you install the project via Nuget. The PostLoad method contains the few lines that execute the Initialize method of each CodeFirstDataprovider.
var dbs = global::Sitecore.Configuration.Factory.GetDatabases();
foreach (var db in dbs)
{
var provider = db.GetDataProviders().FirstOrDefault(x => x is GlassDataProvider) as GlassDataProvider;
if (provider != null)
{
using (new SecurityDisabler())
{
provider.Initialise(db);
}
}
}
Furthermore I would advise to use code first on development only. You can create packages or serialize the templates as usual and deploy them to other environment so you dont need the dataprovider (and potential risks) there.
You can. But it's not going to be Glass related.
Code first is exactly what Sitecore.PathFinder is looking to achieve. There's not a lot of info publicly available on this yet however.
Get started here: https://github.com/JakobChristensen/Sitecore.Pathfinder

System.NullReferenceException Context.Item.Axes.SelectSingleItem

I recently added the Sitecore WebAPI nuget package and have been getting null reference errors when hitting any controller method that makes a reference to my base settings item. My base settings item is defined as follows:
public static class ItemReferences
{
private const string _configurationItemQueryByName = ".//ancestor::*[##templateid='{{SOME_ID}}']/../Settings";
public static Item GetConfigurationItem()
{
return Context.Item.Axes.SelectSingleItem(_configurationItemQueryByName);
}
}
I'm guessing it has to do with this being in a static context but I don't want to take it out of a static context because it doesn't change and many pieces of the website use it.
You are getting an exception because Context.Item is always null on your controller.
Try to change it so it uses Context.Database.GetItem() to get your configuration item.

ATL COM class registration .rgs file defaults

I'm creating a COM server executable, and have run into a problem with class registration. When I created my class object, the automatically generated .rgs file looked like this:
HKCR
{
NoRemove CLSID
{
ForceRemove {4C6DAD45-64B4-4C55-81C6-4CE125226421} = s 'Test Class'
{
ForceRemove Programmable
LocalServer32 = s '%MODULE%'
{
val ServerExecutable = s '%MODULE_RAW%'
}
TypeLib = s '{EAA173CA-BDBC-463A-8B7A-B010EFA467BC}'
Version = s '1.0'
}
}
}
This created the registry entries correctly for the CLSID. However, when attempting to call CoCreateInstance externally, I was experiencing a hang.
hr = CoCreateInstance( __uuidof(Test), NULL, CLSCTX_ALL, __uuidof(ITest), (void**)&pTest);
After looking at a few other projects for examples, I noticed that they all had registry entries of the type:
HKEY_CLASSES_ROOT\<MODULE>.<CLASS>
HKEY_CLASSES_ROOT\<MODULE>.<CLASS>\CLSID
I investigated the .rgs files for these classes, and noticed they had extra entries not present in my .rgs file. I added them to mine, changing it to:
HKCR
{
TestModule.Test = s 'Test Class'
{
CLSID = s '{4C6DAD45-64B4-4C55-81C6-4CE125226421}'
}
NoRemove CLSID
{
ForceRemove {4C6DAD45-64B4-4C55-81C6-4CE125226421} = s 'Test Class'
{
ForceRemove Programmable
LocalServer32 = s '%MODULE%'
{
val ServerExecutable = s '%MODULE_RAW%'
}
TypeLib = s '{EAA173CA-BDBC-463A-8B7A-B010EFA467BC}'
Version = s '1.0'
}
}
}
And lo and behold, my CoCreateInstance call no longer hung, and I was able to properly retrieve a pointer to an ITest interface.
Now, my question is, with the above particulars in mind, how can I ensure that any future classes I create have this correct .rgs file format? Is there some option I'm missing when creating the class objects? Or will I need to manually add the above for every class I create?
I'm using Visual Studio 2010.
That's the ProgID for the coclass. It is primarily used by scripting languages, the ones that use late binding. CreateObject() is the usual function name. That this has anything to do with a hang is unexplainable, you'd better debug it.
The .rgs entry is otherwise automatically generated by the ATL wizard. The ProgID edit box is the lower right one. It doesn't get filled in automatically like the rest of them, you probably missed it.
Sorry for coming five years later...
I got a similar issue with ATL COM wizard using Visual Studio 2015 pro.
(error 0x80080005 - Server execution failed)
It looks like a bug on the ATL COM wizard (since some VS releases, and still not corrected on the latest VS2015).
I found an answer with a manual correction on this MS page:
https://connect.microsoft.com/VisualStudio/feedback/details/782281/catlservicemodulet-not-registering-components
The above link is no longer available. However, the issue is explained in this blog:
https://blogs.msdn.microsoft.com/jigarme/2008/05/07/cocreateinstance-returns-0x80080005-for-visual-studio-2008-based-atl-service/
Basically, the wizard fails to add the AppID registry entry in the associated rgs file:
NoRemove CLSID
{
ForceRemove {...} = s '...'
{
...
val AppID = s '%APPID%'
}
}
The .rgs files are not completely filled by the wizard.
Hope this helps.