I am playing around with Sharepoint 2007. I have a virtual machine (win server 2k3) with an instance of sharepoint server 2007 running on it. I am now working on creating web parts. I have successfully created simple ones, such as this one that displays text:
public class SimpleWebPart : WebPart
{
private string _displayText = "Hello World!";
[WebBrowsable(true), Personalizable(true)]
public string DisplayText
{
get { return _displayText; }
set { _displayText = value; }
}
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.Write(_displayText);
}
}
I have this one (and a few test ones) inside of a Class Library, which I put into the _app_bin folder inside of C:\Inetpub\wwwroot\wss\VirtualDirectories\80.
The latest one I added utilizes LINQ to get data from a table I added (not part of Sharepoint):
public class SimpleDBWebPart : WebPart
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
var oDB = new SPWebPartDataClassesDataContext();
var oRes = oDB.GetAllFirstTable();
foreach(var item in oRes)
{
writer.Write("<div>Item Name: {0}</div>",item.text);
writer.Write("<div>Item ID: {0}</div>", item.id);
}
}
}
The GetAllFirstTable() is a stored procedure that gets all the data from my test table:
ALTER PROCEDURE dbo.GetAllFirstTable
AS
SELECT * FROM FirstTable
RETURN
When I try to add the WebPart to a page, I get this error:
The "SimpleDBWebPart" Web Part appears to be causing a problem. Could not load file or assembly 'System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The system cannot find the file specified.
I used Reflector to make sure I have the assembly inside the DLL:
And that appears to be the case. Do I have to add the assembly to the web.config file of the sharepoint site? Or is there something else that I am missing?
Thanks guys!
To use LINQ or .NET 3.5 feature you need to first configure the SharePoint to run in 3.5 Mode.
Refer to these links on how to do that
Simplest way
AnotherOne
Related
I have a C# Solution containing two projects : Client (parent) and RestAPI (child). From the client project, I'm loading a ASP.NET server. Currently, my RestAPI is successfully loading controllers from the client project using services.AddControllersWithViews().AddApplicationPart(assembly);. Currently, only the controllers can be loaded, though, I want to use some views too.
To summarize, what I'm trying to do is to use views that are located into my Client project by the RestAPI project.
What I've tried to do :
services.AddControllersWithViews().AddApplicationPart(assembly); => It loads only the controllers
services.AddMvc().AddApplicationPart(assembly); => Same results
Returning a static path to the view file (i.e. : return View("C:\Simon\...");)
Project structure :
In the controller DevicesController.cs, I have to following function:
[Route("show")]
[HttpGet]
public ViewResult Show()
{
return View("Home");
}
I want to return the view in the Views folder located under Client project. However, It only returns the one located under RestAPI. If I remove the one in RestAPI, the application crashes with the following error logs :
System.InvalidOperationException: The view 'Home' was not found. The following locations were searched:
/Views/Devices/Home.cshtml
/Views/Shared/Home.cshtml
I think you have to consider adding relatedAssemblies.
private static void AddApplicationPart(IMvcBuilder mvcBuilder, Assembly assembly)
{
var partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly);
foreach (var part in partFactory.GetApplicationParts(assembly))
{
mvcBuilder.PartManager.ApplicationParts.Add(part);
}
var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(assembly, throwOnError: false);
foreach (var relatedAssembly in relatedAssemblies)
{
partFactory = ApplicationPartFactory.GetApplicationPartFactory(relatedAssembly);
foreach (var part in partFactory.GetApplicationParts(relatedAssembly))
{
mvcBuilder.PartManager.ApplicationParts.Add(part);
}
}
}
I'm trying to implement a generic approach for providing the possibility for different assemblies in my web solution to use embedded JavaScript and CSS files from embedded resources. This blog post shows a technique using a VirtualPathProvider. This works fine, but the VirtualPathProvider needs to be included in each assembly containing embedded resources.
I tried to enhance the VirtualPathProvider from the blog post, so that an assembly can be passed into it and it loads the resource from its assembly:
public EmbeddedVirtualPathProvider(VirtualPathProvider previous, Assembly assembly)
{
this.previous = previous;
this.assembly = assembly;
}
On initialization it reads all embedded resources from the passed assembly:
protected override void Initialize()
{
base.Initialize();
this.assemblyResourceNames = this.assembly.GetManifestResourceNames();
this.assemblyName = this.assembly.GetName().Name;
}
And the GetFilereads the content from the passed assembly:
public override VirtualFile GetFile(string virtualPath)
{
if (IsEmbeddedPath(virtualPath))
{
if (virtualPath.StartsWith("~", System.StringComparison.OrdinalIgnoreCase))
{
virtualPath = virtualPath.Substring(1);
}
if (!virtualPath.StartsWith("/", System.StringComparison.OrdinalIgnoreCase))
{
virtualPath = string.Concat("/", virtualPath);
}
var resourceName = string.Concat(this.assembly.GetName().Name, virtualPath.Replace("/", "."));
var stream = this.assembly.GetManifestResourceStream(resourceName);
if (stream != null)
{
return new EmbeddedVirtualFile(virtualPath, stream);
}
else
{
return _previous.GetFile(virtualPath);
}
}
else
return _previous.GetFile(virtualPath);
}
Checking if resource is an embedded resource of this assembly is by checking the resource names read in the Initialize method:
private bool IsEmbeddedPath(string path)
{
var resourceName = string.Concat(this.assemblyName, path.TrimStart('~').Replace("/", "."));
return this.assemblyResourceNames.Contains(resourceName, StringComparer.OrdinalIgnoreCase);
}
I moved the EmbeddedVirtualPathProvider class to the main web project (ProjectA), so that it doesn't need to be included in each assembly containing embedded resources and registered it using the following code in Global.asax:
HostingEnvironment.RegisterVirtualPathProvider(
new EmbeddedVirtualPathProvider(
HostingEnvironment.VirtualPathProvider,
typeof(ProjectB.SomeType).Assembly));
In the project containing the embedded resources (ProjectB) I still create the following bundle in a PostApplicationStartMethod:
BundleTable.Bundles.Add(new ScriptBundle("~/Embedded/Js")
.Include("~/Scripts/SomeFolder/MyScript.js")
);
Scripts/MyScript.js is the embedded resource in ProjectB.
With this I receive the following exception:
Directory 'C:\webs\ProjectA\Scripts\SomeFolder\' does not exist. Failed to start monitoring file changes.
Update
Full stack trace available in this Gist.
Update
Also the VirtualPathProvider itself seems to work fine. If I load the file directly and not through the bundle and set the following entry in the web.config it loads the embedded javascript from ProjectB:
<system.webServer>
<handlers>
<add name="MyStaticFileHandler" path="*.js" verb="GET,HEAD" type="System.Web.StaticFileHandler"/>
</handlers>
</system.webServer>
When ASP.net optimization create the bundle it call GetCacheDependency for the virtual directory of the script. Your GetCacheDependency implementation only check virtual file, for virtual directory it relies on the base VirtualPathProvider which check if directory exists and failed.
To solve this issue, you have to check if the path is a directory of one of your script and return null for the GetCacheDependency.
To safely determine if virtualPath is a bundle directory, you can use the BundleTable.Bundles collection or using a convention (ie: every bundle should starts with ~/Embedded).
public override CacheDependency GetCacheDependency(
string virtualPath,
IEnumerable virtualPathDependencies,
DateTime utcStart)
{
// if(virtualPath.StartsWith("~/Embedded"))
if(BundleTables.Bundles.Any(b => b.Path == virtualPath))
{
return null;
}
if (this.IsEmbeddedPath(virtualPath))
{
return null;
}
else
{
return this._previous
.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
}
Regarding below error
Directory 'C:\webs\ProjectA\Scripts\SomeFolder\' does not exist. Failed to start monitoring file changes.
This happens specifically if all resource files of the SomeFolder are embedded and thus in published site - it does not have this folder created.
In case of bundle - it keeps timestamp when the bundle is created and it monitors the folder for any file change to trigger update in the bundle file.
Here - no files in the SomeFolder to monitor - as all are embedded. Didn't find to prevent the folder monitoring - but by handling this specific exception, it can be ignored.
I am trying to test mef and mefcontrib in asp.net mvc2 app but i got an error:
Cannot cast the underlying exported value of type LoggerExtSys.Domain.WebLogger
(ContractName="LoggerExtSys.Domain.IWebLogger") to type LoggerExtSys.Domain.IWebLogger.
My test project here
code in Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
var catalog = new CatalogBuilder()
.ForAssembliesInDirectory(HttpRuntime.BinDirectory, "*ExtSys.dll")
.Build();
// Create interception configuration
var cfg = new InterceptionConfiguration()
.AddInterceptor(new StartableStrategy());
// Create the InterceptingCatalog with above configuration
var interceptingCatalog = new InterceptingCatalog(catalog, cfg);
// Create the container
var container = new CompositionContainer(interceptingCatalog);
// exception here
var barPart = container.GetExportedValue<IWebLogger>();
barPart.Debug("Test");
}
Exception when i try to get GetExportedValue
code in WebLogger:
[Export(typeof(IWebLogger))]
public class WebLogger : IWebLogger
{
#region IWebLogger Members
public void Debug(string str)
{
}
#endregion
#region ICoreExtension Members
public void Initialize()
{
}
#endregion
}
But in desktop app all working good.
How to fix it? Thanks for all
Ok, the problem was in code block which load assemblies:
public AggregateCatalog ForAssembliesInDirectory(string directory, string pattern)
{
IList<ComposablePartCatalog> _catalogs = new List<ComposablePartCatalog>();
var dir = new DirectoryInfo(directory);
Assembly assembly;
foreach (var file in dir.GetFiles(pattern))
{
assembly = Assembly.LoadFile(file.FullName);
_catalogs.Add(new AssemblyCatalog(assembly));
}
return new AggregateCatalog(_catalogs);
}
After all test i remove it and use DirectoryCatalog. I dont know why but its work in desktop and web app.
Who will tell me why my old code not working in web app will get accepted answer and 50 bounty. Thanks for all
I think the problem is either here:
[Export(typeof(IWebLogger))]
public class WebLogger : IWebLogger
{
or in the way you handle type referencing and resolution.
I would try to change the line:
var barPart = container.GetExportedValue<IWebLogger>();
into:
var barPart = container.GetExportedValue<WebLogger>();
or you can also try to always use fully qualified names so not only IWebLogger but put its full namespace before.
you say this works well in windows based application, what assemblies did you reference in that project or how do you write in there the content of your Application_Start event handler? Are you sure it's absolutely the same?
Traditionally I use the regular asp.net website (created using the File > New Website). Recently, I opted to work off of a full fledged project (created using File > New Project > ASP.net Web Application).
I've been using the same custom controls for years without incident. I simply create the new website, place my CustomControls.cs file in the App_Code directory, add one line to the web.config file and I can use all of my custom server controls.
When I try that with my web project I get the following error
Error 225 The
type or namespace name 'DTF' could not
be found in the global namespace (are
you missing an assembly
reference?) D:[Project Location On
Drive]\AgIn02.aspx.designer.cs
My custom control file looks like this
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using AjaxControlToolkit;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
namespace DTF.Web.UI
{
public class IntOnlyBox : TextBox
{
private RequiredFieldValidator rfv;
private ValidatorCalloutExtender vce;
private AjaxControlToolkit.FilteredTextBoxExtender ftb;
private string strInvalidMessage = "";
private string strValidationGroup = "";
public string ValidationGroup
{
get
{
return strValidationGroup;
}
set
{
strValidationGroup = value;
}
}
public string InvalidMessage
{
get
{
return strInvalidMessage;
}
set
{
strInvalidMessage = value;
}
}
protected override void OnInit(EventArgs e)
{
rfv = new RequiredFieldValidator();
rfv.ControlToValidate = this.ID;
rfv.ErrorMessage = "<span style=\"color:black\"><b>Required Field Missing</b><br />" + this.InvalidMessage + "</span>";
//rfv.ErrorMessage = this.InvalidMessage;
rfv.ID = "rfv" + this.ID;
rfv.Display = ValidatorDisplay.None;
rfv.SetFocusOnError = true;
rfv.EnableClientScript = true;
rfv.ValidationGroup = this.ValidationGroup;
vce = new AjaxControlToolkit.ValidatorCalloutExtender();
vce.ID = "vce" + this.ID;
vce.TargetControlID = "rfv" + this.ID;
vce.Width = 300;
ftb = new FilteredTextBoxExtender();
ftb.ID = "ftb" + this.ID;
ftb.TargetControlID = this.ID;
ftb.FilterType = FilterTypes.Numbers;
Controls.Add(rfv);
Controls.Add(vce);
Controls.Add(ftb);
}
protected override void Render(HtmlTextWriter w)
{
//w.Write(this.InvalidMessage);
base.Render(w);
rfv.RenderControl(w);
vce.RenderControl(w);
ftb.RenderControl(w);
}
}
}
my web.config entry looks like this (in the pages/controls area)
<add tagPrefix="DTF" namespace="DTF.Web.UI" />
I've tried everything I can think of to get this to work and compile. The intellisense for the custom server controls works fine, it simply won't compile.
I also get the error "The base class
includes the field 'blanro', but its
type (DTF.DateBoxFull) is not
compatible with the type of control
(DTF.DateBoxFull)."
Any idea how to fix this, and why it would work in the regular asp.net website but not in a web project?
Thanks Everyone.
Compile your custom classes to a .dll and add a reference to your project.
Well, to answer it simply WAP and Web Site have a different way of compiling the applications and hence you may be seeing this behavior.
When using a WAP, it's best not to put your custom control in App_Code. Instead, simply put that code somewhere else in your project, and you should be able to use the control from your pages without problems.
The App_Code directory in a WebApplication project has no effect. All code files, regardless of the directory in which it resides, are compiled into a single assembly, and that assembly is placed in the bin directory.
Just move all your files out of App_Code and then delete App_Code.
I have my own custom tool for Visual Studio 2008 SP1. It consists of 5 assemblies: 3 assemblies with code that are used heavily in my other projects, 1 assembly-wrapper above VS2008 SDK and an assembly with the tool.
If I'd debug my tool from visual studio, using "Run external program" option with command line "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe" and arguments "/ranu /rootsuffix Exp" all works perfectly.
After that I'm trying to deploy it to my working VS copy, not to experimental hive, doing: gacutil /i Asm1.dll for all my assemblies and doing RegAsm Asm1.dll only for assembly with custom tool. Neither of utils prints any error, all work as planned, even registry keys appear. But my tool doesn't work (error occurred "Cannot find custom tool 'TransportGeneratorTool' on this system") even after PC restart. What did I do wrong?
Wrapper looks like that:
[ComVisible(true)]
public abstract class CustomToolBase : IVsSingleFileGenerator, IObjectWithSite
{
#region IVsSingleFileGenerator Members
int IVsSingleFileGenerator.DefaultExtension(out string pbstrDefaultExtension)
{
pbstrDefaultExtension = ".cs";
return 0;
}
int IVsSingleFileGenerator.Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
{
GenerationEventArgs gea = new GenerationEventArgs(
bstrInputFileContents,
wszInputFilePath,
wszDefaultNamespace,
new ServiceProvider(Site as Microsoft.VisualStudio.OLE.Interop.IServiceProvider)
.GetService(typeof(ProjectItem)) as ProjectItem,
new GenerationProgressFacade(pGenerateProgress)
);
if (OnGenerateCode != null)
{
OnGenerateCode(this, gea);
}
byte[] bytes = gea.GetOutputCodeBytes();
int outputLength = bytes.Length;
rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(outputLength);
Marshal.Copy(bytes, 0, rgbOutputFileContents[0], outputLength);
pcbOutput = (uint)outputLength;
return VSConstants.S_OK;
}
#endregion
#region IObjectWithSite Members
void IObjectWithSite.GetSite(ref Guid riid, out IntPtr ppvSite)
{
IntPtr pUnk = Marshal.GetIUnknownForObject(Site);
IntPtr intPointer = IntPtr.Zero;
Marshal.QueryInterface(pUnk, ref riid, out intPointer);
ppvSite = intPointer;
}
void IObjectWithSite.SetSite(object pUnkSite)
{
Site = pUnkSite;
}
#endregion
#region Public Members
public object Site { get; private set; }
public event EventHandler<GenerationEventArgs> OnGenerateCode;
[ComRegisterFunction]
public static void Register(Type type)
{
using (var parent = Registry.LocalMachine.OpenSubKey(#"Software\Microsoft\VisualStudio\9.0", true))
foreach (CustomToolRegistrationAttribute ourData in type.GetCustomAttributes(typeof(CustomToolRegistrationAttribute), false))
ourData.Register(x => parent.CreateSubKey(x), (x, name, value) => x.SetValue(name, value));
}
[ComUnregisterFunction]
public static void Unregister(Type type)
{
using (var parent = Registry.LocalMachine.OpenSubKey(#"Software\Microsoft\VisualStudio\9.0", true))
foreach (CustomToolRegistrationAttribute ourData in type.GetCustomAttributes(typeof(CustomToolRegistrationAttribute), false))
ourData.Unregister(x => parent.DeleteSubKey(x, false));
}
#endregion
}
My tool code:
[ComVisible(true)]
[Guid("55A6C192-D29F-4e22-84DA-DBAF314ED5C3")]
[CustomToolRegistration(ToolName, typeof(TransportGeneratorTool))]
[ProvideObject(typeof(TransportGeneratorTool))]
public class TransportGeneratorTool : CustomToolBase
{
private const string ToolName = "TransportGeneratorTool";
public TransportGeneratorTool()
{
OnGenerateCode += GenerateCode;
}
private static void GenerateCode(object s, GenerationEventArgs e)
{
try
{
var serializer = new XmlSerializer(typeof (Parser.System));
using (var reader = new StringReader(e.InputText))
using (var writer = new StringWriter(e.OutputCode))
{
Generator.System = (Parser.System) serializer.Deserialize(reader);
Generator.System.Namespace = e.Namespace;
Generator.GenerateSource(writer);
}
}
catch (Exception ex)
{
e.Progress.GenerateError(ex.ToString());
}
}
}
Resulting registry keys:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Generators\{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}\TransportGeneratorTool]
#="TransportGeneratorTool"
"CLSID"="{55a6c192-d29f-4e22-84da-dbaf314ed5c3}"
"GeneratesDesignTimeSource"=dword:00000001
"GeneratesSharedDesignTimeSource"=dword:00000001
Here is the code of my custom attribute (it is in wrapper assembly):
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class CustomToolRegistrationAttribute : RegistrationAttribute
{
public CustomToolRegistrationAttribute(string name, Type customToolType)
{
Name = name;
CustomToolType = customToolType;
}
/// <summary>
/// The type that implements the custom tool. This starts
/// as MyCustomTool by default in the template.
/// </summary>
public Type CustomToolType { get; set; }
public string Name { get; set; }
#region RegistrationAttribute abstract member implementations
public override void Register(RegistrationContext context)
{
Register(x => context.CreateKey(x), (x, key, value) => x.SetValue(key, value));
}
public void Register<T>(Func<string, T> keyCreator, Action<T, string, object> valueCreator)
{
var keyName = CreateKeyName(Name);
var key = keyCreator(keyName);
valueCreator(key, string.Empty, Name);
valueCreator(key, "CLSID", CustomToolType.GUID.ToString("B"));
valueCreator(key, "GeneratesDesignTimeSource", 1);
valueCreator(key, "GeneratesSharedDesignTimeSource", 1);
var disposable = key as IDisposable;
if (disposable != null)
disposable.Dispose();
}
private static string CreateKeyName(string name)
{
return string.Format(#"Generators\{0}\{1}", vsContextGuids.vsContextGuidVCSProject, name);
}
public override void Unregister(RegistrationContext context)
{
Unregister(context.RemoveKey);
}
public void Unregister(Action<string> keyRemover)
{
keyRemover(CreateKeyName(Name));
}
#endregion
}
My solution is to make a setup project. I get the registry settings from the pkgdef file by adding the following to the csproj file of the package:
<Target Name="GeneratePackageRegistryFiles">
<Exec Command=""$(VSSDK90Install)VisualStudioIntegration\Tools\Bin\RegPkg.exe" /root:Software\Microsoft\VisualStudio\9.0 /codebase "$(TargetPath)" /regfile:"$(OutDir)$(TargetName).reg"" />
</Target>
<PropertyGroup>
<BuildDependsOn>$(BuildDependsOn);GeneratePackageRegistryFiles;</BuildDependsOn>
</PropertyGroup>
When building look in the output directory you should find a .reg file which you can import in the setup project.
Obviously you can run the regpkg.exe from the command-line if modifying the project is not an option.
This is what I ended up with last time when I struggled to get my custom tool registered.
I hope this instruction is detailed enough and covers everything so you won't spend much time fighting it. The following MSDN article was used as a starting point. http://msdn.microsoft.com/en-US/library/bb166527(v=vs.80).aspx Unfortunately you cannot use it alone. What you really need to do is:
Make sure the assembly is signed. Why? Because otherwise you won't be able to put it into GAC at step 6 below.
To sign your assembly follow these steps:
1.1. Go to the Properties screen of the project.
1.2. Once there go to the Signing tab.
1.3. Once there check the Sign the assembly checkbox.
Make sure you know the version number of your assembly. You will need this number to specify the ASSEMBLY_VERSION parameter later.
In order to get this number open the AssemblyInfo.cs file in the Properties folder of your project and look for the line starting with: [assembly: AssemblyVersion(
Make sure you know the GUID of the generator class. You will need it to specify the GENERATOR_GUID parameter later.
In order to get this GUID open the file with the generator class and look for the Guid class-attribute that decorates this class, something like: [Guid("17799E85-421B-4684-B59E-650E34ECC718")]
Build the project
Get the public token key of the assembly. In order to do that you will have to run the following command:
sn.exe -T ASSEMBLY_FILE
You will need this information later when for PUBLIC_TOKEN_KEY.
The sn.exe file can be found in C:\Program Files\Microsoft SDKs\Windows\v8.0A\bin\sn.exe
Pay attention to the version number of the framework (v8.0A) in the filepath above. It needs to be consistent with the version of the framework used to compile the project.
Put the assembly to the GAC using the following command:
gacutil.exe /i ASSEMBLY_FILE /f
Getting registered in GAC requires administrative permissions.
The gacutil.exe file can be found in C:\Program Files\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\gacutil.exe
Pay attention to the version number of the framework (v8.0A) in the filepath above. It needs to be consistent with the version of the framework used to compile the project.
Make the following changes to the .REG (see below) file. PLEASE NOTE: that both GENERATOR_GUID and PROJECT_TYPE_GUID need to be supplied WITH curly braces: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
7.1. Fix version number of Visual Studio is used (for example: 10.0 or 9.0): VS_VERSION
7.2. Fix the GUID of the generator: GENERATOR_GUID
7.3. Fix the namespace of the assembly: NAMESPACE_NAME
7.4. Fix the generator class name: GENERATOR_TYPE_NAME
7.5. In order to register the generator the Visual Studio needs to know to which project types this generator can be applied to. So you need to get GUID's of proper project types (C#, VB.NET, etc.).
To figure out the GUID's of the project types you need to open a visual studio project file (*.csproj) in a text editor and look for GUID's in the ProjectTypeGuids XML element.
For each of these GUIDs repeat the block of last 3 entries in the .REG file replacing the PROJECT_TYPE_GUID with the a GUID just found.
7.6. Fix the extension of the file associated with the custom tool: FILE_EXTENSTION
Run the .REG file. You may need to have administrative permissions for doing this.
.REG file:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\CLSID\GENERATOR_GUID]
#="COM+ class: NAMESPACE_NAME.GENERATOR_TYPE_NAME"
"InprocServer32"="C:\\WINDOWS\\system32\\mscoree.dll"
"ThreadingModel"="Both"
"Class"="NAMESPACE_NAME.GENERATOR_TYPE_NAME"
"Assembly"="NAMESPACE_NAME, Version=ASSEMBLY_VERSION, Culture=Neutral, PublicKeyToken=PUBLIC_TOKEN_KEY"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID]
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID\\.FILE_EXTENSTION]
#="GENERATOR_TYPE_NAME"
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\VS_VERSION\Generators\PROJECT_TYPE_GUID\GENERATOR_TYPE_NAME]
#="Code generator for whatever you like"
"CLSID"="GENERATOR_GUID"
"GeneratesDesignTimeSource"=dword:00000001
PS.
Sorry for not being able to make placehoders in the REG file distinct, unfortunately the text editor that StackOverflow uses cannot distinguish its markup elements from the content.