Resolving incorrect project reference GUIDs - visual-studio-2010

I have some projects in a Visual Studio solution that have ended up with project references that include the wrong GUID for the referenced project. (Possibly due to the referenced project being recreated at some stage)
eg. Consider a project CoreProject.csproj with the following properties:
<ProjectGuid>{93803F9C-8C65-4949-8D44-AB7A3D0452C8}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>CoreProject</RootNamespace>
<AssemblyName>CoreProject</AssemblyName>
Another project includes a reference to this, but at some stage the GUID has changed and is now incorrect.
<ProjectReference Include="..\CoreProject\CoreProject.csproj">
<Project>{5FD52517-79F8-41D2-B6F2-EA2D8A886549}</Project>
<Name>CoreProject</Name>
</ProjectReference>
The solution still loads and builds correctly in Visual Studio and msbuild, but I suspect having the wrong GUIDs may have some performance impact within VS.
The solution is quite large with many projects that have this issue, and I'd prefer not to have to re-add these references manually. Are there any tools or macros that can 'fix' up the project reference GUIDs?

I think a basic console app should do the trick, something like this:
using System;
using System.IO;
using System.Linq;
using Microsoft.Build.Evaluation;
public class Program
{
public static void Main(String[] args)
{
var projects = Directory.EnumerateFiles(#"...", "*.csproj", SearchOption.AllDirectories)
.Select(x =>
{
try
{
return new Project(x);
}
catch
{
return null;
}
})
.Where(x => x != null)
.ToList();
var guids = projects.ToDictionary(p => p.FullPath, p => p.GetPropertyValue("ProjectGuid"));
foreach (var project in projects)
{
var save = false;
foreach (var reference in project.GetItems("ProjectReference"))
{
var path = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(project.FullPath), reference.EvaluatedInclude));
if (!guids.ContainsKey(path))
{
Console.WriteLine("No {0}", Path.GetFileName(path));
continue;
}
var guid = guids[path];
var meta = reference.GetMetadataValue("Project");
if (meta != guid)
{
Console.WriteLine("{0} -> {1}", meta, guid);
reference.SetMetadataValue("Project", guid);
save = true;
}
}
if (save)
project.Save(project.FullPath);
}
}
}

Related

Visual studio how to add custom tool/code generator configuration options

I wanted to easily turn some json schema files into classes. So googling I found NJsonSchema and I implemented this in a visual studio custom tool so I can set this on relevant json files and get my classes out. This al works and I pasted the code below. This code comes from this very answer. Though it does need a little updating for VS2022.
I find that documentation on how to do this is rather rare and the thing I am missing is how I can add something like configuration options for the custom tool.
Take for example the line "ClassStyle = CSharpClassStyle.Record," that is something one might want configurable for the user. But I cannot find anything on how to do that. Anyone have a good pointer/answer on this?
Preferably a way to add take the config from some custom properties in the file its properties that are available when the custom tool is configured on a project file.
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System.Text;
using NJsonSchema.CodeGeneration.CSharp;
using NJsonSchema;
namespace ClassGeneratorForJsonSchema
{
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("GenerateClassesFromJsonSchema", "Use NJsonSchema to generate code from a json schema.", "1.0")]
[Guid("202E7E8B-557E-46CB-8A1D-3024AD68F44A")]
[ComVisible(true)]
[ProvideObject(typeof(ClassGeneratorForJsonSchema))]
[CodeGeneratorRegistration(typeof(ClassGeneratorForJsonSchema), "ClassGeneratorForJsonSchema", "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}", GeneratesDesignTimeSource = true)]
public sealed class ClassGeneratorForJsonSchema : IVsSingleFileGenerator
{
#region IVsSingleFileGenerator Members
public int DefaultExtension(out string pbstrDefaultExtension)
{
pbstrDefaultExtension = ".cs";
return pbstrDefaultExtension.Length;
}
public int Generate(string wszInputFilePath, string bstrInputFileContents,
string wszDefaultNamespace, IntPtr[] rgbOutputFileContents,
out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
{
try
{
var schema = JsonSchema.FromJsonAsync(bstrInputFileContents).Result;
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings()
{
JsonLibrary = CSharpJsonLibrary.SystemTextJson,
ClassStyle = CSharpClassStyle.Record,
Namespace = wszDefaultNamespace
});
byte[] bytes = Encoding.UTF8.GetBytes(generator.GenerateFile());
int length = bytes.Length;
rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(length);
Marshal.Copy(bytes, 0, rgbOutputFileContents[0], length);
pcbOutput = (uint)length;
}
catch (Exception ex)
{
pcbOutput = 0;
}
return VSConstants.S_OK;
}
#endregion
}
}

How to use different custom renderer on different versions of Android in Xamarin Forms?

I have Xamarin Forms solution and in Xamarin Droid project I have custom renderer for class CustomCameraScanView that extends ContentView. This CustomCameraScanView should use Camera (old API) on Androids before 5.0 (Lollipop) and Camera2 (new API) from 5.0 and afterwards. How can I create two renderers: CustomCameraScanViewRenderer_Droid4 and CustomCameraScanViewRenderer_Droid5 that will be used on different versions of OS?
My CustomCameraScanViewRenderer_Droid4 looks like this:
[assembly: ExportRenderer(typeof(CustomCameraScanView), typeof(CustomCameraScanViewRenderer_Droid4))]
namespace Genea.Droid.Renderers
{
public class CustomCameraScanViewRenderer_Droid4 : ViewRenderer,
ISurfaceTextureListener,
ISurfaceHolderCallback,
Android.Hardware.Camera.IPreviewCallback,
Android.Hardware.Camera.IPictureCallback,
Android.Hardware.Camera.IShutterCallback
{
}
}
Unfortunately, registering a custom-renderer at runtime is not possible at this point in Xamarin-Forms. More details can be found on this forum link. But what you can do is resolve the controls at run-time using OnPlatform and build-version number.
I would of course recommend the conditional-compilation approach first as suggested by #luccas-clezar; but if that is not an option, then you can try resolving your control (and hence the renderer) at run-time using following steps.
Steps:
Create an simple contract to resolve current API value - in forms project
public interface IBuildVersion { int Number { get; } }
Implement it for Android platform
public class AndroidBuildVersion : IBuildVersion
{
public int Number { get { return ((int)Android.OS.Build.VERSION.SdkInt); } }
}
Register on DependencyService
[assembly: Xamarin.Forms.Dependency (typeof (AndroidBuildVersion))]
Subclass your CustomCameraScanView into two derived types - in forms project
public class CustomCameraScanView_Droid4 : CustomCameraScanView { }
public class CustomCameraScanView_Droid5 : CustomCameraScanView { }
Setup your renderers in Android project
[assembly: ExportRenderer(typeof(CustomCameraScanView_Droid4), typeof(CustomCameraScanViewRenderer_Droid4))]
and,
[assembly: ExportRenderer(typeof(CustomCameraScanView_Droid5), typeof(CustomCameraScanViewRenderer_Droid5))]
Create custom-control to resolve at run-time - using OnPlatform - in forms project
public class CameraScanContentView : Xamarin.Forms.ContentView
{
public CameraScanContentView()
{
this.Content = Device.OnPlatform(
iOS: new CustomCameraScanView(),
Android: DependencyService.Get<IBuildVersion>().Number < 21
? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
: ((CustomCameraScanView)new CustomCameraScanView_Droid5()),
WinPhone: new CustomCameraScanView()
);
}
}
And, XAML usage will look like this
<local:CameraScanContentView />
Update 05/24
I don't believe Xamarin-Forms supports 'Property Value' inheritance as WPF does - so it is kind of tricky to propagate the values from parent to child control.
One option is to cascade these values back to CustomCameraScanView from CameraScanContentView by defining bindable-properties (recommended):
public class CameraScanContentView : Xamarin.Forms.ContentView
{
public CameraScanContentView()
{
CustomCameraScanView scannerCtrl = null;
switch (Device.RuntimePlatform)
{
case Device.Android:
scannerCtrl = DependencyService.Get<IBuildVersion>().Number < 21
? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
: ((CustomCameraScanView)new CustomCameraScanView_Droid5());
break;
default:
scannerCtrl = new CustomCameraScanView();
break;
}
scannerCtrl.SetBinding(CustomCameraScanView.IsScanningProperty, new Binding(nameof(IsScanning), source: this));
scannerCtrl.SetBinding(CustomCameraScanView.IsTakingImageProperty, new Binding(nameof(IsTakingImage), source: this));
scannerCtrl.SetBinding(CustomCameraScanView.IsFlashlightOnProperty, new Binding(nameof(IsFlashlightOn), source: this));
Content = scannerCtrl;
}
public static readonly BindableProperty IsScanningProperty = BindableProperty.Create("IsScanning", typeof(bool), typeof(CameraScanContentView), false);
public static readonly BindableProperty IsTakingImageProperty = BindableProperty.Create("IsTakingImage", typeof(bool), typeof(CameraScanContentView), false);
public static readonly BindableProperty IsFlashlightOnProperty = BindableProperty.Create("IsFlashlightOn", typeof(bool), typeof(CameraScanContentView), false);
public bool IsScanning
{
get { return (bool)GetValue(IsScanningProperty); }
set { SetValue(IsScanningProperty, value); }
}
public bool IsTakingImage
{
get { return (bool)GetValue(IsTakingImageProperty); }
set { SetValue(IsTakingImageProperty, value); }
}
public bool IsFlashlightOn
{
get { return (bool)GetValue(IsFlashlightOnProperty); }
set { SetValue(IsFlashlightOnProperty, value); }
}
}
XAML usage will then look like this
<local:CameraScanContentView IsScanning="{Binding IsScanning}" IsFlashlightOn="{Binding IsFlashlightOn}" IsTakingImage="{Binding IsTakingImage}" />
Or, you can manually define your binding-expressions as below (not recommended as it makes the assumption that the property-names on view-model will not change):
public class CameraScanContentView : Xamarin.Forms.ContentView
{
public CameraScanContentView()
{
CustomCameraScanView scannerCtrl = null;
switch (Device.RuntimePlatform)
{
case Device.Android:
scannerCtrl = DependencyService.Get<IBuildVersion>().Number < 21
? ((CustomCameraScanView)new CustomCameraScanView_Droid4())
: ((CustomCameraScanView)new CustomCameraScanView_Droid5());
break;
default:
scannerCtrl = new CustomCameraScanView();
break;
}
scannerCtrl.SetBinding(CustomCameraScanView.IsScanningProperty, new Binding("IsScanning", source: this.BindingContext));
scannerCtrl.SetBinding(CustomCameraScanView.IsTakingImageProperty, new Binding("IsTakingImage", source: this.BindingContext));
scannerCtrl.SetBinding(CustomCameraScanView.IsFlashlightOnProperty, new Binding("IsFlashlightOn", source: this.BindingContext));
Content = scannerCtrl;
}
}
Note: My first instinct was to use an implicit style targeting CustomCameraScanView to bind the values - but somehow couldn't get it to work.
There's no need to have two renderers I think. Something like this should work:
if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop)
{
// Access old API
}
else
{
// Access new API
}
Another method of doing the same thing is by adding compiler directives. Like so:
#if __ANDROID_21__
// New API (>=21)
#else
// Old API (<21)
#endif
This will compile only the specific code of that Android API. I'm not sure if this works with PCL projects and the only thing that I could find that said something about it is this line from Dealing with Multiple Platforms guide: "Conditional compilation works best with Shared Asset Projects, where the same source file is being referenced in multiple projects that have different symbols defined.". Anyway, I think you could give it a try.
Hope it helps! :)
You will probably have to put some code like the code below inside the renderers so their methods don't get called unless a certain platform requirement is met:
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
// Lollipop specific stuff
}
There is no mechanism in place to actually point to a different renderer on different OS versions.
You can put the following code in your main activity right after Forms.Init() (if you are using forms)
if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
Xamarin.Forms.Internals.Registrar.Registered.Register(typeof(Xamarin.Forms.Picker), typeof(PickerRendererEx));
}
else
{
Xamarin.Forms.Internals.Registrar.Registered.Register(typeof(Xamarin.Forms.Picker), typeof(PickerRendererExOld));
}

ASP.NET Web API Help Pages and Versioning

I would like to create a separate help page for each version of my API. For example, the user could go to /help?v=1 to see version 1.0 routes and /help?v=2 to see version 2.0 routes.
Using SDammann.WebApi.Versioning, I added a Version property to VersionedApiExplorer that will return only the routes for the defined version and added the version as an argument to the constructor. Then I tried this:
config.Services.Add(typeof(IApiExplorer), new VersionedApiExplorer(config, "1"));
config.Services.Add(typeof(IApiExplorer), new VersionedApiExplorer(config, "2"));
But this gives me the following error:
The service type IApiExplorer is not supported.
Parameter name: serviceType
I added just one instance of the service - config.Services.Replace(typeof(IApiExplorer), new VersionedApiExplorer(GlobalConfiguration.Configuration, "1")); - to get the configuration to work, so I could test my help controller. Then tried this:
foreach (var service in Configuration.Services.GetServices(typeof(IApiExplorer))) {
if (service.GetType() != typeof(VersionedApiExplorer)) continue;
var explorer = service as VersionedApiExplorer;
if (explorer.Version == v) {
apiExplorer = explorer;
}
}
This gives the same error I received above. I know I would normally use this.Configuration.Services.GetApiExplorer() but I don't know how I could use that to get the appropriate instance of VersionedApiExplorer. I know I could instantiate the appropriate ApiExplorer directly in the controller, but I would prefer to keep that in my configuration file if possible.
So I have two questions:
How could I add two services of type VersionedApiExplorer to my config object?
How would I retrieve the appropriate service in my help controller?
Or is there a completely different approach I could take to accomplish the same goal?
Thank you!
I ultimately ended up going with the solution I hinted at in my question. I feel like there's a better solution to this problem, but this gets the job done.
First, I added a Version property to VersionedApiExplorer:
public string Version { get; private set; }
Then I modified InitializeApiDescriptions to look like this:
private Collection<ApiDescription> InitializeApiDescriptions()
{
Collection<ApiDescription> apiDescriptions = new Collection<ApiDescription>();
var controllerSelector = configuration.Services.GetHttpControllerSelector();
IDictionary<string, HttpControllerDescriptor> allControllerMappings = controllerSelector.GetControllerMapping();
IDictionary<string, HttpControllerDescriptor> controllerMappings = new Dictionary<string, HttpControllerDescriptor>();
// get only mappings for defined version
if (allControllerMappings != null && Version != null) {
foreach (var key in allControllerMappings.Keys) {
if (key.Substring(0, key.IndexOf('.')) == VersionedControllerSelector.VersionPrefix + Version) {
controllerMappings.Add(key, allControllerMappings[key]);
}
}
}
else if (Version == null) {
controllerMappings = allControllerMappings;
}
if (controllerMappings != null)
{
foreach (var route in configuration.Routes)
ExploreRouteControllers(controllerMappings, route, apiDescriptions);
}
return apiDescriptions;
}
I also added a method I could use to set the Version:
public void SetVersion(string version) {
this.Version = version;
this.apiDescription = new Lazy<Collection<ApiDescription>>(InitializeApiDescriptions);
}
Finally, I modified my HelpController to looks like this:
public ActionResult Index(string v) {
return this.View(GetApiExplorer(v).ApiDescriptions);
}
private IApiExplorer GetApiExplorer(string version) {
if (version == null) {
version = "1";
}
var apiExplorer = this.Configuration.Services.GetApiExplorer() as VersionedApiExplorer;
if (apiExplorer != null) {
apiExplorer.SetVersion(version);
}
return apiExplorer;
}

MVC 3: AutoMapper and Project/Solution Structure

I've just started to use AutoMapper in my MVC 3 project and I'm wondering how people here structure their projects when using it. I've created a MapManager which simply has a SetupMaps method that I call in global.asax to create the initial map configurations. I also need to use a ValueResolver for one of my mappings. For me, this particular ValueResolver will be needed in a couple of different places and will simply return a value from Article.GenerateSlug.
So my questions are:
How do you manage the initial creation of all of your maps (Mapper.CreateMap)?
Where do you put the classes for your ValueResolvers in your project? Do you create subfolders under your Model folder or something else entirely?
Thanks for any help.
i won't speak to question 2 as its really personal preference, but for 1 i generally use one or more AutoMapper.Profile to hold all my Mapper.CreateMap for a specific purpose (domaintoviewmodel, etc).
public class ViewModelToDomainAutomapperProfile : Profile
{
public override string ProfileName
{
get
{
return "ViewModelToDomain";
}
}
protected override void Configure()
{
CreateMap<TripRegistrationViewModel, TripRegistration>()
.ForMember(x=>x.PingAttempts, y => y.Ignore())
.ForMember(x=>x.PingResponses, y => y.Ignore());
}
}
then i create a bootstrapper (IInitializer) that configures the Mapper, adding all of my profiles.
public class AutoMapperInitializer : IInitializer
{
public void Execute()
{
Mapper.Initialize(x =>
{
x.AddProfile<DomainToViewModelAutomapperProfile>();
x.AddProfile<ViewModelToDomainAutomapperProfile>();
});
}
}
then in my global.asax i get all instances of IInitializer and loop through them running Execute().
foreach (var initializer in ObjectFactory.GetAllInstances<IInitializer>())
{
initializer.Execute();
}
that's my general strategy.
by request, here is the reflection implementation of the final step.
var iInitializer = typeof(IInitializer);
List<IInitializer> initializers = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => iInitializer.IsAssignableFrom(p) && p.IsClass)
.Select(x => (IInitializer) Activator.CreateInstance(x)).ToList();
foreach (var initializer in initializers)
{
initializer.Execute();
}

Get solution folder name in TFS 2010

I am struggling to get solution folder names in the TFS drop locations.
I have a .NET solution file in the following hirerchy:
Solution File
--> Solution Folder A --> Project A
--> Solution Folder B --> Project B & Project C
Now I want my drop location should be customized like the above project hierarchy.
means : in the Drop Location it should be : SolutionName -> SolutionFolderName -> ProjectName -> {build output}
By implementing customize output directory in my build template , i.e. $(TeamBuildOutDir)\$(SolutionName)\$(MSBuildProjectName), I am getting Solution Name -> Project Name -> Build outputs..
But I am not getting Solution Folder names to structure my outputs. Can anybody suggest how to get this so that I can read from my project files.
Thanks in advance.
You could set a property in the projects that corresponds to the solution folder name (e.g. $(SolutionFolder)). Then you could set the output directory to $(TeamBuildOutDir)\$(SolutionFolder).
public static TeamProject[] GetAllProjects(TfsTeamProjectCollection prjCollection)
{
var versionControl = prjCollection.GetService<VersionControlServer>();
return versionControl.GetAllTeamProjects(true);
}
public static ProjectCollection GetAllIterations(TfsTeamProjectCollection prjCollection)
{
var wiStore = prjCollection.GetService<WorkItemStore>();
return wiStore.Projects;
}
/// <summary>
/// function to get all system project name
/// </summary>
private void IterateFolder()
{
try
{ var selectedProject = "EMRConversion";
Project detailsOfTheSelectedProject = null;
var projCollections = GetAllIterations(prjCollection);
foreach (Project project in projCollections)
{
if (!String.IsNullOrEmpty(selectedProject))
{
if (project.Name.ToString().Contains(selectedProject))
{
detailsOfTheSelectedProject = project;
break;
}
}
}
if (detailsOfTheSelectedProject != null)
{
cmbSystemName.Items.Clear();
foreach (Node area in detailsOfTheSelectedProject.AreaRootNodes)
{
if (!(area.HasChildNodes))
{
cmbSystemName.Items.Add(area.Name);
}
foreach (Node item in area.ChildNodes)
{
cmbSystemName.Items.Add(item.Name);
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}

Resources