VB.NET multithreading - vb.net

I need to do a taks on a list of parameters: all those tasks are independant.
I don't see how to do it.. I tried to divide the parameters into one "shared class" and make a different instance of a class for each item in the list, and then launch the function on each instance asynchroneously :
Imports System.Runtime.InteropServices
Imports System.IO
Public Class DataContainer
Public Parameters as double 'obviously simplified code ;-)
End Class
Public Class JobDoer
Public CommonData As DataContainer
Public PrivData as double
Public Async Function YesWeCan() As Task(Of Boolean)
Return Task.Factory.StartNew(Of Boolean)(
DoIt(CommonData.Parameters , PrivData)
)
End Function
Public Function DoIt(a as double,b as double)
return 0
end function
End Class
==> Task is not defined...
.NET framework 3.0
VS 2015
Any ideas?

The Async and Await keywords are not available in .NET 3.0. They have been introduced in .NET 4.5, although you can already make use of them in 4.0 (with some modifications, like having to use TaskEx instead of Task for some of the static functions) if you import the Microsoft.Bcl.Async package via NuGet.
You can of course simply start new threads without having to use Async/Await.
Or you could use the ThreadPool. Here is some code I made back in the past, which was originally written in C#. I converted it now and removed the parts that would require at least .NET 4.0. Didn't test it, though.
Private Sub SubmitWorkToThreadPool()
For i as Integer = 0 To yourWorkItems.Count 'Adjust this loop so it adds all your tasks to the thread pool.
'customParameter is passed as parameter 'state' to the DoParallelWork function.
ThreadPool.QueueUserWorkItem(AddressOf DoParallelWork, customParameter)
Next
End Sub
Private Sub DoParallelWork(state As Object)
'TODO: Add code to be executed on the threadpool
End Sub
In the 4.0 version I had it written in a way that would allow me to wait for all work items to be completed after submitting it to the threadpool by using a CountdownEvent. But that class only exists since 4.0, so I removed it. You might have to find another way if you need to wait for everything to be done.

Related

Translating C# functions into vb.net

I need help converting some of this code. Mainly:
private static void SetProvider(ServiceCollection collection)
=> _service = collection.BuildServiceProvider();
and the line below it. This is being used for a discord bot using Discord.Net with the music library Victoria. Can someone also tell me what this actually is? Just a side question. this uses static classes and there's not anything called static on VB.Net so what would be the best call here? I've seen some other posts from here debating whether to use NonInheritable Class or a Module. What are the differences and when it is better to use either one?
It depends on what you want exactly. VB.NET does not provide static classes. Instead, it offers modules, but those are not completely equal to static classes.
The module version would be:
Public Module ServiceManager
Private _service As IServiceProvider
Public Sub SetProvider(collection As ServiceCollection)
_service = collection.BuildServiceProvider()
End Sub
Public Function GetService(Of T As New)() As T
Return _service.GetRequiredService(Of T)()
End Function
End Module
The class version would be:
Public NotInheritable Class ServiceManager
Private Sub New()
End Sub
Private Shared _service As IServiceProvider
Public Shared Sub SetProvider(collection As ServiceCollection)
_service = collection.BuildServiceProvider()
End Sub
Public Shared Function GetService(Of T As New)() As T
Return _service.GetRequiredService(Of T)()
End Function
End Class
When using the class implementation, you have to be careful to mark all members as Shared. Additionally, you can consider the following:
Declare the class as NotInheritable, since neither VB.NET modules nor C# static classes can be inherited from. (The corresponding C# keyword is sealed, by the way, but it will never be used in this context, since C# does support static classes.)
Create one private (default) constructor for the class. That will make sure that you cannot instantiate the class. VB.NET modules nor C# static classes cannot be instantiated either.
Using VB.NET modules is somewhat more straightforward, but keep in mind that VB.NET modules have a little quirk. When accessing a member of a module, you are typically not required to prefix it with the module name. Suppose you have some kind of service class called MyService and you have implemented your ServiceManager as a module. Then you do not need to call it like:
Dim svc As MyService = ServiceManager.GetService(Of MyService)()
Instead, you could just call it like:
Dim svc As MyService = GetService(Of MyService)()`.
When using the former method, Visual Studio actually suggests to simplify the name and change it to the latter method. But when you afterwards add another imported namespace that also happens to contain a module that has a GetService(Of T)() method, you will get an error indicating that GetService is ambiguous, in which case you would be forced to prefix it with the module name (like in the former method).
I personally find this checking behavior in Visual Studio regarding VB.NET module member usage to be rather annoying and confusing. I prefer prefixing calls with the module name (for the sake of writing self-documenting code and avoiding ambiguity as mentioned), but I do not want to disable the "simplify name" hint/suggestion in Visual Studio. So I personally prefer a class implementation instead of a module implementation when implementing something in VB.NET that mimics a C# static class.
Or even better: I would avoid a static class design and switch to a "regular" class design when possible. Using class instances has several advantages, like using composition (which is also an important technique used in many popular behavioral design patterns), simplified mocking/unittesting, and less side effects in general.
The equivalent VB.NET is:
Private Shared Sub SetProvider(collection As ServiceCollection)
_service = collection.BuildServiceProvider()
End Sub
C# expression bodies are just a single expression body method, MS Docs e.g. the following are equivalent:
void Greet()
{
Console.WriteLine("Hello World");
}
// Same as above
void Greet() => Console.WriteLine("Hello World");

C# to VB6 COM events (“object or class does not support the set of events”), but different

I am aware of a 10 year old question with the same title as this one but I have double checked and I am not mistakenly using the delegate name. This is a different issue.
Here at work we have an old VB6 application I need to teach new(er) tricks. The first thing I had to do was have it call methods from a .Net COM-visible DLL written in C#. I have that working. Now I need to have it handle incoming progress notification events from that same DLL. I asked a similar question yesterday wherein the VB6 IDE was not even seeing that the DLL had events to offer. That issue was solved by decorating the C# interfaces and classes correctly.
First, the C# codez:
namespace NewTricksDLL
{
[ComVisible(true)]
[Guid("16fb3de9-3ffd-4efa-ab9b-0f4117259c75")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITransfer
{
[DispId(2)]
string SendAnEvent();
}
[ComVisible(true)]
[Guid("16fb3de9-3ffd-4efa-ab9b-0f4117259c74")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IManagedEventsToCOM
{
[DispId(2)]
void NotificationEvent();
}
[ComVisible(true)]
[Guid("dcf177ab-24a7-4145-b7cf-fa06e892ef21")]
[ComSourceInterfaces(typeof(IManagedEventsToCOM))]
[ProgId("ADUTransferCS.NewTricks")]
public class NewTricks : ITransfer
{
public delegate void NotificationEventHandler();
public event NotificationEventHandler NotifificationEvent;
public string SendAnEvent()
{
if (NotifificationEvent != null)
NotifificationEvent();
}
}
}
An now my attempt to use it in VB6. Please note that the _tricky_NotificationEvent event handler was generated by the IDE by picking _tricky from the left-hand dropdown and NotificationEvent from the right-hand dropdown so I know this event is visible to the VB6 IDE.
Option Explicit
Public WithEvents _tricky As NewTricksDLL.NewTricks
Private Sub Command1_Click()
' The next line fails with 'Object or class does not support the set of events'
Set _tricky = CreateObject("NewTricksDLL.NewTricks")
' Execution never makes to the next line
_tricky.SendAnEvent()
End Sub
Private Sub _tricky_NotificationEvent()
' This handler was auto generated by the IDE
End Sub
Hopefully this can help - here's a minimal bare bones VB.net implementation of your requirements: COM interface consumable by VB6, one event, one method.
Option Explicit On
Option Strict On
<ComClass(newTricks.ClassId, newTricks.InterfaceId, newTricks.EventsId)>
Public Class newTricks
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "386d540d-f8b8-46e1-939d-7b69dd5eff0a"
Public Const InterfaceId As String = "78b4036e-86a0-4671-997d-da5a33bf026f"
Public Const EventsId As String = "7b0fa5b5-b45e-4db2-9282-c06e09852161"
#End Region
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Public Sub New()
MyBase.New()
End Sub
Public Event NotificationEvent()
Public Sub SendAnEvent()
RaiseEvent NotificationEvent()
End Sub
End Class
This was created by starting a new project (Windows class library), delete from the project the Class1.vb that's automatically created, add a COM Class item renaming it to NewTricks. Then added the event declaration and the sub declaration and code; also added the Option statements. Built the project.
This was successfully used from this VB6 code. Clicking the button resulted in "Event fired" being written to the immediate window. This was successful with using both New and CreateObject methods of creating the reference to newTricks.
Option Explicit
Private WithEvents oTricks As NewTricksDll.newTricks
Private Sub Command1_Click()
Set oTricks = New NewTricksDll.newTricks
'Set oTricks = CreateObject("NewTricksDll.newTricks")
oTricks.SendAnEvent
End Sub
Private Sub oTricks_NotificationEvent()
Debug.Print "Event fired"
End Sub
Here is the corresponding C# code for the VB.net code, as converted straight-up by https://converter.telerik.com/
using Microsoft.VisualBasic;
[ComClass(newTricks.ClassId, newTricks.InterfaceId, newTricks.EventsId)]
public class newTricks
{
// These GUIDs provide the COM identity for this class
// and its COM interfaces. If you change them, existing
// clients will no longer be able to access the class.
public const string ClassId = "386d540d-f8b8-46e1-939d-7b69dd5eff0a";
public const string InterfaceId = "78b4036e-86a0-4671-997d-da5a33bf026f";
public const string EventsId = "7b0fa5b5-b45e-4db2-9282-c06e09852161";
// A creatable COM class must have a Public Sub New()
// with no parameters, otherwise, the class will not be
// registered in the COM registry and cannot be created
// via CreateObject.
public newTricks() : base()
{
}
public event NotificationEventEventHandler NotificationEvent;
public delegate void NotificationEventEventHandler();
public void SendAnEvent()
{
NotificationEvent?.Invoke();
}
}
I have not tried this C# code.
If you use CreateObject, it creates an object of type Object I believe. You should create the object simply by using New:
Set _tricky = New NewTricksDLL.NewTricks
Since you declared the variable as WithEvents, you can't just declare it using As New NewTricksDLL.NewTricks which I imagine you probably tried.

How does one override the default SQL migration generator?

I'm attempting to override the default behavior of the SQL migrations generator so that I may specify a custom foreign key constraint name, as discussed here. I've wired up the configuration as advised.
Unfortunately, however, it's not going so well.
A quick logging statement reveals that the GetFkName() function is never hit.
I tried an alternate configuration construct, as discussed here and here, but I'm getting this error when I attempt to generate a migration:
More than one migrations configuration type was found in the assembly 'ConsoleApp1'. Specify the name of the one to use.
I find this result a bit odd, as I have only one configuration class, one SQL generation class, and one context class (the code below doesn't reflect this, but I commented out the extras for my actual tests). Specifying the configuration type on the command line, as indicated here, errors with this:
System.InvalidOperationException: The type 'ConsoleApp1.Db.CustomDbConfiguration2' does not inherit from 'System.Data.Entity.DbConfiguration'. Entity Framework code-based configuration classes must inherit from 'System.Data.Entity.DbConfiguration'.
All of this brings us back here, then, which doesn't work for the aforementioned reason (GetFkName() never gets hit). So it seems I'm chasing my tail (didn't know I had one until today).
What should I do to get this override to work correctly?
Configuration
Imports System.Data.Entity
Imports System.Data.Entity.Migrations
Imports System.Data.Entity.SqlServer
Namespace Db
Friend Class CustomDbConfiguration
Inherits DbConfiguration
Public Sub New()
Me.SetMigrationSqlGenerator(SqlProviderServices.ProviderInvariantName, Function() New CustomSqlGenerator)
End Sub
End Class
Friend Class CustomDbConfiguration2
Inherits DbMigrationsConfiguration(Of Context)
Public Sub New()
Me.SetSqlGenerator(SqlProviderServices.ProviderInvariantName, New CustomSqlGenerator2(Me.GetSqlGenerator(SqlProviderServices.ProviderInvariantName)))
Me.ContextType = GetType(Context)
End Sub
End Class
End Namespace
SQL Generator
Imports System.Data.Entity.Migrations.Model
Imports System.Data.Entity.Migrations.Sql
Imports System.Data.Entity.SqlServer
Namespace Db
Friend Class CustomSqlGenerator
Inherits SqlServerMigrationSqlGenerator
Protected Overrides Sub Generate(AddForeignKeyOperation As AddForeignKeyOperation)
AddForeignKeyOperation.Name = GetFkName(AddForeignKeyOperation.PrincipalTable, AddForeignKeyOperation.DependentTable, AddForeignKeyOperation.DependentColumns.ToArray())
MyBase.Generate(AddForeignKeyOperation)
End Sub
Protected Overrides Sub Generate(DropForeignKeyOperation As DropForeignKeyOperation)
DropForeignKeyOperation.Name = GetFkName(DropForeignKeyOperation.PrincipalTable, DropForeignKeyOperation.DependentTable, DropForeignKeyOperation.DependentColumns.ToArray())
MyBase.Generate(DropForeignKeyOperation)
End Sub
Private Shared Function GetFkName(PrimaryKeyTable As String, ForeignKeyTable As String, ParamArray ForeignTableFields As String()) As String
IO.File.WriteAllText("D:\Logs\FkNameTest.log", $"{Now.ToString}{vbCrLf}")
Return $"FK_{ForeignKeyTable}_{PrimaryKeyTable}"
End Function
End Class
Friend Class CustomSqlGenerator2
Inherits MigrationSqlGenerator
Public Sub New(Generator As MigrationSqlGenerator)
Me.Generator = Generator
End Sub
Public Overrides Function Generate(MigrationOperations As IEnumerable(Of MigrationOperation), ProviderManifestToken As String) As IEnumerable(Of MigrationStatement)
Return Me.Generator.Generate(MigrationOperations, ProviderManifestToken)
End Function
Private ReadOnly Generator As MigrationSqlGenerator
End Class
End Namespace
Context
Imports System.Data.Common
Imports System.Data.Entity
Imports System.Data.SqlClient
Imports System.Reflection
Namespace Db
<DbConfigurationType(GetType(CustomDbConfiguration2))>
Friend Class Context
Inherits DbContext
Public Sub New()
MyBase.New(DbConnection.ConnectionString)
End Sub
Private Sub New(Connection As DbConnection)
MyBase.New(Connection, True)
Database.SetInitializer(New CreateDatabaseIfNotExists(Of Context))
Database.SetInitializer(New MigrateDatabaseToLatestVersion(Of Context, Migrations.Configuration))
Me.Database.Initialize(False)
End Sub
Public Shared Function Create() As Context
Return New Context(DbConnection)
End Function
Private Shared ReadOnly Property DbConnection As SqlConnection
Get
Return New SqlConnection(Utils.DbConnectionString)
End Get
End Property
Protected Overrides Sub OnModelCreating(Builder As DbModelBuilder)
Builder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly)
MyBase.OnModelCreating(Builder)
End Sub
Public Property Documents As DbSet(Of Document)
Public Property Sections As DbSet(Of Section)
End Class
End Namespace
Disclaimer: I haven't coded in VB for many years, these code examples are my feeble attempt to translate my working example in C# into OPs native VB. Please feel free to update my syntax ;)
You can manually edit the migration scripts to specify a custom name for each ForeignKey by specifying a value for the optional Name parameter in the call to Tablebuilder.ForeignKey as part of a create table statement:
CreateTable(
"dbo.CorporationVariety",
Function(c) New With
{
.Id = c.Int(nullable: false, identity:= true),
.CorporationId = c.Int(nullable:= false),
.VarietyId = c.Int(nullable:= false),
}) _
.PrimaryKey(Function(t) t.Id)
.ForeignKey("dbo.Corporation", Function(t) t.CorporationId, name := "FKCorporatationCorporationVarietyCorporationId")
.ForeignKey("dbo.Variety", Function(t) t.VarietyId, name := "FKVarietyCorporationVarietyVarietyId")
.Index(Function(t) t.CorporationId)
.Index(Function(t) t.VarietyId)
Or as part of a DbMigration.AddForeignKey statement:
AddForeignKey("dbo.CorporationVariety", "CorporationId", "dbo.Corporation", name := "FKCorporatationCorporationVarietyCorporationId")
AddForeignKey("dbo.CorporationVariety", "VarietyId", "dbo.Variety", name := "FKVarietyCorporationVarietyVarietyId")
If you have a lot of keys in your Model, and you want to implement a specific convention, (as in a standard rule or sequence of code that you want to apply in given scenarios) across all keys, then Normally the first place to look for a solution is EF Code First Conventions.
Unfortunately, there is neither a standard convention that can help you here nor can you define a custom name for a foreign key using fluent notation...
Normally we would go ahead and create a Custom Code First Convention to define your custom logic, this works in generally 2 ways:
Your convention executes standard configuration via Fluent Notation
we already noted that this option is not available to us...
Your convention logic stores custom metadata to the model via annotations
Primary and Foreign keys seem to be an anomaly in the EF Code First Runtime, there does not seem to be a way to easily access the annotations from the associations even though they are relatively easy to define.
I was surprised to find this and stumbled across this post that further confirms this: https://stackoverflow.com/a/54369685/1690217
Update I started this post assuming that Conventions was the right way to go, because I use it for many other customisations that I've needed to apply over the years. If you are looking to implement other similar types of customisations, look to Conventions first.
We can still easily override the standard VisualBasicMigrationCodeGenerator that generates the migration code files, so lets jump straight into that.
coapply to custom name for your ForeignKey and then implement a custom MigrationCodeGenerator to process the output from your convention.
Create a custom VisualBasicMigrationCodeGenerator
Register the Code Generator so that it is used by EF to generate the next migration
NOTE: This will not force existing keys in your database to be renamed. To do that you would need to force each key to be dropped and re-added back. For a large model Consider using a T4 template to create custom once-off migration logic to achieve this, once the above steps are in place.
Think of your Custom VisualBasicMigrationCodeGenerator as your personal EF code first sour dough culture, you can share this and re-use it for every new application, adding new functionality and improvements with each iteration. But Conventions are the configuration options that you may not want in every project, (which is why using _Conventions_ for OPs solution was my first direction.)
1. Create a custom VisualBasicMigrationCodeGenerator
Create a new class that inherits from the EF VisualBasicMigrationCodeGenerator, the minimal we need to do is override the AddForeignKeyOperation and modify the Name of the key and call the base implementation. This will affect all new keys added to the model.
To target keys added as part of CreateTable we will have to override GenerateInline(AddForeignKeyOperation...), however the base implemention (in the C# Generator...) doesn't obey the custom Name so instead we have to replace the implementation entirely.
When doing this, goto the EF project on GitHub and start with the original implementation, then inject your customizations as needed.
Please excuse this C#, I didn't have time to translate it, it does generate the correct VB code though ;)
public class CustomVBMigrationCodeGenerator : System.Data.Entity.Migrations.Design.VisualBasicMigrationCodeGenerator
{
protected override void Generate(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
{
ApplyCustomFKName(addForeignKeyOperation);
base.Generate(addForeignKeyOperation, writer);
}
private void ApplyCustomFKName(ForeignKeyOperation operation)
{
// expecting FK without scheme or underscores: "FK{DependentTable}{PrincipalTable}{FKField}"
operation.Name = $"FK{StripSchemeFromName(operation.DependentTable)}{StripSchemeFromName(operation.PrincipalTable)}{String.Join("", operation.DependentColumns)}";
}
private string StripSchemeFromName(string dbObjectName)
{
return dbObjectName.Split(new[] { '.' }, 2).Last();
}
/// <summary>
/// Generates code to perform an <see cref="AddForeignKeyOperation" /> as part of a <see cref="CreateTableOperation" />.
/// </summary>
/// <param name="addForeignKeyOperation"> The operation to generate code for. </param>
/// <param name="writer"> Text writer to add the generated code to. </param>
protected virtual void GenerateInline(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
{
// sourced from https://github.com/aspnet/EntityFramework6/blob/master/src/EntityFramework/Migrations/Design/VisualBasicMigrationCodeGenerator.cs
Check.NotNull(addForeignKeyOperation, "addForeignKeyOperation");
Check.NotNull(writer, "writer");
writer.WriteLine(" _");
writer.Write(".ForeignKey(" + Quote(addForeignKeyOperation.PrincipalTable) + ", ");
Generate(addForeignKeyOperation.DependentColumns, writer);
// Our Custom logic
ApplyCustomFKName(addForeignKeyOperation);
// Insert our custom name if provided
if (!addForeignKeyOperation.HasDefaultName)
{
writer.Write(", name := " + Quote(addForeignKeyOperation.Name));
}
if (addForeignKeyOperation.CascadeDelete)
{
writer.Write(", cascadeDelete := True");
}
writer.Write(")");
}
}
2. Register the Code Generator so that it is used by EF to generate the next migration
Locate Configuration.vb in your project, int the constructor set the CodeGenerator to an instance of your CustomVBMigrationCodeGenerator :
Public Sub New()
AutomaticMigrationsEnabled = false
CodeGenerator = new CustomVBMigrationCodeGenerator()
End Sub
Now execute the add-migration to generate a new migration you will see you new custom name defined in the migration script.
You may be required to similarly override the Generate(DropForeignKeyOperation...) methods as well if you need to downgrade from this configuration _or_ if alter table commands require the key to be dropped first.

Can a class library use function stored in main project?

In my VB.NET application, I would like to move some code (a class) into a separate file. The separate file will use functions located in the main project.
If I create a Class Library, functions called from the DLL are not defined in the DLL and Visual Studio won't compile it.
In what ways could I move code into file and load/execute it at runtime and get the result the my main code? I don't know if I'm clear...
This can be done indirectly using interfaces. Create a public interface in the library that has the calls you need to make against that main project's class. Have the main project's class implement this interface. When the main projects starts have it pass in instance of this class in to the library project via the interface. The library should store this reference. It can now makes calls against the main projects class using this reference through the interface.
The Library Project:
Public Interface ITimeProvider
ReadOnly Property Time As Date
End Interface
Public Class LibraryClass
Private Shared _timeProvider As ITimeProvider
Public Shared Sub Init(timeProvider As ITimeProvider)
_timeProvider = timeProvider
End Sub
Public Function GetTimeString() As String
Return "The current time is " & _timeProvider.Time.ToString
End Function
End Class
The Main Project:
Public Class SimpleTimeProvider
Implements ClassLibrary1.ITimeProvider
Public ReadOnly Property Time As Date Implements ClassLibrary1.ITimeProvider.Time
Get
Return Date.Now
End Get
End Property
End Class
Public Class MainClassTest
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
ClassLibrary1.LibraryClass.Init(New SimpleTimeProvider)
Dim test As New ClassLibrary1.LibraryClass
Console.WriteLine(test.GetTimeString)
End Sub
End Class
This example has the library project using a class that is defined in the Main project.
Simple answer is - you can't.
You can't have assemblyA referencing assemblyB and assemblyB referencing assemblyA
The solution is probably to move any code that is used by both your application and assembly into the assembly. Then both can access this code

CruiseControl .Net Plugin Vb.net Error

I am trying to make my own Labeller plugin for Cruise Control .Net 1.4.3. I have made a class based on another plug in example but I keep getting an error
Class 'AssemblyVersionLabeller' must implement 'Function Generate(integrationResult As IIntegrationResult) As String' for interface 'ThoughtWorks.CruiseControl.Core.ILabeller'
Here is my code :
Imports Exortech.NetReflector
Imports ThoughtWorks.CruiseControl.Core
Imports ThoughtWorks.CruiseControl.Core.Util
Namespace NetAssembly.CCNet.Label
_
Public Class AssemblyVersionLabeller
Implements ILabeller
Public Sub Run(ByVal result As IIntegrationResult)
result.Label = Generate(result)
End Sub
Public Function Generate(ByVal integrationResult As IIntegrationResult) As String
Dim label As String = integrationResult.LastIntegration.Label
Return label
End Function
<ReflectorProperty("prefix", Required:=False)> _
Public Prefix As String = String.Empty
End Class
End Namespace
What am I doing wrong? What have I missed?
Background Info:
I am using VS2005. I cant use CrusieControl 1.4.4 RC2 (which has an Assembly Labeller) because my source control's plugin (SCM Anywhere) doesnt work with it.
I cannot judge just by looking at your code, but if you need a sample on how to write labellers (C# code though), you could take a look at BrekiLabeller code (written by me).
I believe you forgot the overrides decleration..
Public Overrides Function Generate