Intellisense not finding vb.net Extension - vb.net

I created an extension method in VB.NET in Visual Studio 2013 but it will not show up in Intellisense.
Imports System.Security.Claims
Imports System.Runtime.CompilerServices
Imports Connect.Common.Portable
Namespace Authorization
Public Module ClaimsPrincipalExtensions
<Extension()>
Public Function CurrentFirmNumber(ByVal principal As ClaimsPrincipal) As Integer
Dim c As Claim = principal.FindFirst(AuthorizationClaimTypes.LOGGED_IN_FIRM_NUMBER)
If (c IsNot Nothing) Then
Dim firmNumber As Integer = 0
If (Integer.TryParse(c.Value, firmNumber)) Then
Return firmNumber
End If
End If
Return 0
End Function
End Module
End Namespace
I have tried everything I could find on StackOverflow and other sites to solve this to no avail, including everything mentioned here.
In my calling code I include the right namespace, and the compiler and runtime are perfectly happy if I call this extension. That is, the code runs fine and correctly calls the extension method. It is simply intellisense that doesn't show it to me.
However, if I try to reference the method directly using the full namespace, as opposed to from the extended object, it shows up in intellisense.
Any ideas?
UPDATE:
So, it gets weirder. I had a colleague open up the same source and he gets intellisense.
As well, original extensions that used to work for me now have the same intellisense problem. However, if I start typing out the extension name intellisense does see it once it becomes a unique name.
For example, If I type "CurrentPrincipal.Current.C" Intellisense suggests "Claims", but not "CurrentFirmNumber", as that is part of the type. However, if I add a "u" it then suggests "CurrentFirmNumber", which is my extension.

Related

vba Run-time error '429': ActiveX can't create object, with user defined vb.net dll (VB.NET 2017, Excel 2016)

I have written a simple dll in VB.NET 2017, and I am trying to call it from VBA (Excel 2016). I have searched through Stack Overflow and MSDN, but despite many hits for this VBA error, I cannot find information related to a user defined dll that solves this particular problem.
I checked the box for the Register for COM Interop option when compiling the dll. I also verified that the Make assembly COM-Visible box was also checked.
Compilation was successful, and I was able to find my library (called TestLibrary2) in References inside the VBA editor. The class I created in it is called TestVBNET. I checked TestLibrary2 to include it in VBA, and then attempted to run the following code in VBA:
Public Sub mySub()
Dim myTest2 As TestLibrary2.TestVBNet
Set myTest2 = New TestLibrary2.TestVBNet
End Sub
When I ran the sub, I got the pop-up dialog with message: Run-time error '429': ActiveX can't create object
Based on what I have read on MSDN and other sites, the expected result is that the TestLibrary2.TestVBNet object should be instantiated successfully.
The code below is the VB.NET code that I compiled to the dll. The GUID's were generated using guidgen at the Windows 10 command prompt.
Imports System.Runtime.InteropServices
<Guid("2CEBF80D-D5FC-4C52-BCF1-E2F076318240")>
Public Interface ITestVBNet
Function addTrig(x As Double, y As Double) As Double
End Interface
<Guid("60983277-A724-4CDD-8ACE-B94CF9546F43")>
<ClassInterface(ClassInterfaceType.None)>
Public Class TestVBNet
Function addTrig(x As Double, y As Double) As Double
Return Math.Sin(x) + Math.Cos(x)
End Function
End Class
Any help and or references would be greatly appreciated. Thanks in advance.
EDIT (per comments below): I compiled the dll as admin, which in fact was required for the Register for COM Interop option to run. I also tried using regasm -- also as admin -- as follows, in the same directory as the compiled dll:
regasm /codebase /tlb TestLibrary2.dll
The following was returned:
RegAsm : warning RA0000 : Registering an unsigned assembly with /codebase can cause your assembly to interfere with other applications that may be installed on the same computer. The /codebase switch is intended to be used only with signed assemblies. Please give your assembly a strong name and re-register it.
Types registered successfully
RegAsm : error RA0000 : An error occurred while saving the exported type library: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
I apologize for being a newb here with respect to registering COM libraries, but what this seemed to indicate was the dll was registered successfully, but could not be transferred to the GAC. It was my intention not to transfer it. When I tried loading it in VBA, the same error as above occurred.
It turns out that the above code compiled to a dll that was indeed callable from a C# client. The problem with VBA, however, was that I neglected to put Implements ITestVBNet following the derived class declaration. In VB.NET, though, in addition to this, one must also explicitly indicate function overriding in the derived function declaration as well; viz (scroll all the way to the right to see the entire line),
Public Function addTrig(x As Double, y As Double) As Double Implements ITestVBNet.addTrig
By replacing the derived class above with the following, I was able to create an instance of the TestVBNet object in VBA and call the addTrig(.) method successfully:
<Guid("60983277-A724-4CDD-8ACE-B94CF9546F43")>
<ClassInterface(ClassInterfaceType.None)>
Public Class TestVBNet
Implements ITestVBNet
Public Function addTrig(x As Double, y As Double) As Double Implements ITestVBNet.addTrig
Return Math.Sin(x) + Math.Cos(x)
End Function
End Class

Difficulty Registering/using VB .Net DLL for use in VBA/Com Interop

I have created a library I want to be able to share with colleagues, containing functions they can access from the VBIDE within MSOffice applications. I am using Visual Studio Express 2010, so I haven't been able to get the IDE to automatically register the DLL - instead, I have used RegAsm.exe. After several hours of desperate Googling, I finally managed to get the DLL (TLB) to appear in the VBIDE references menu. Whilst I have lots of classes in the DLL, I only exposed one as a ComClass:
<ComClass(RandomDemographicData.ClassId, RandomDemographicData.InterfaceId, RandomDemographicData.EventsId)> Public Class RandomDemographicData
Public Const ClassId As String = "05DC232D-D584-4739-8DDE-6FCA997EDC0C"
Public Const InterfaceId As String = "8FBD540B-3884-4585-9C90-47E42666FB63"
Public Const EventsId As String = "736CDFDC-D240-4DC7-9BE6-9167054221ED"
Public Function aName() As String
Return "Hello World"
End Function
End Class
Then I called it in VBA with:
Sub fgjhfh()
Dim f As New RandomDemographicData
Debug.Print f.aName
End Sub
But I get error "'-2147024894 (80070002)': Automation Error: system cannot find the file specified". I seem tantalizingly close to my goal, but can't quite make it - is anyone able to help?
EDIT:
The RegAsm command I used was "RegAsm.exe MyVBALib.dll /tlb:MyVBALib.tlb /codebase following advice found in the last post here. I have also made a copy of RegAsm.exe in the folder containing the DLL

In VB.NET does MS require the fully qualified function name for the Right or Left string functions?

According to the Microsoft documentation, to determine the number of characters in str, use the Len function. If used in a Windows Form, or any other class that has a Right property, you must fully qualify the function with "Microsoft.VisualBasic.Strings.Right".
If I set "Imports Microsoft.VisualBasic" at the top of the form I still have to use the fully qualified name in my code. Why does MS require this?
Because, without the fully qualified name, if there are two methods with the same name, the compiler cannot choose one over the other. So you should take care of the problem giving the correct hint
To ease your typing you could add at the top of your code file this version of the Imports statement
Imports VB6 = Microsoft.VisualBasic
and then you could type
Dim stringLen = VB6.Len(yourStringVariable)
This is the MSDN introduction to Namespaces in VB.NET, in particular, in the first lines of the article is explained your problem Avoiding Namespaces Collisions
NET Framework namespaces address a problem sometimes called namespace
pollution, in which the developer of a class library is hampered by
the use of similar names in another library. These conflicts with
existing components are sometimes called name collisions.
For example, if you create a new class named ListBox, you can use it
inside your project without qualification. However, if you want to use
the .NET Framework ListBox class in the same project, you must use a
fully qualified reference to make the reference unique. If the
reference is not unique, Visual Basic produces an error stating that
the name is ambiguous.
And by the way, start to use the equivalent framework methods for Right, Left, and Len.
They are still available only to help the porting of old VB6 application, (and sometime they work differently). In new applications I suggest to use
string.Substring(start, len)
string.Length
A winform, Form (derived from Control), have properties named Right and Left.
Public Class Form1
Inherits Form
Public Sub Test()
Dim location_left As Integer = Me.Left
Dim location_right As Integer = Me.Right
'Or simply:
location_left = Left '<- (Referring to Me.Left, not Microsoft.VisualBasic.Strings.Left)
location_right = Right '<- (Referring to Me.Right, not Microsoft.VisualBasic.Strings.Right)
End Sub
End Class
Therefore you'll need the use the full qualify name.

.net assembly does not appear in Excel's References

I'm following Rich Newman's guide to using .net code assemblies in Excel. I have made a small test class called MyPro[p in a project called MyProperty that looks like this:
Imports System.Runtime.InteropServices
Public Class MyProp
Public Function GetData() As String
Return "Hello World"
End Function
End Class
It compiles fine, puts a CLSID into regedit, and (after browsing to find the TLB) allows itself to be added to Excel's References. However, I can't actually use it. I tried this in VBA:
Private Sub test()
Dim test As New MyProperty.MyProp
MsgBox test.GetData()
End Sub
Which returns:
"Class does not support Automation or does not support the expected interface"
I assume that the error means that it can't find GetData or I'm calling it incorrectly. I have re-added the TLB, with no effect.
Any ideas?
The problem has to do with the order of operations in the bindings. You can make this work by DIMming the object then Newing it on a separate line.

.NET Default Properties Error [duplicate]

This question already has answers here:
Why can I access an item in KeyCollection/ValueCollection by index even if it doesn't implement IList(Of Key)?
(2 answers)
Closed 6 years ago.
I have a VB.NET project where I am able to iterate through the keys and values collections of a dictionary object using an index:
MyDictionary.Keys(idx)
MyDictionary.Values(idx)
When this code is taken from the test project and placed into the real project I get the following error:
'System.Collections.Generic.Dictionary(Of Double, String).KeyCollection' cannot be indexed because it has no default property.
and
'System.Collections.Generic.Dictionary(Of Double, String).ValueCollection' cannot be indexed because it has no default property.
This is using VB.NET and VS 2008. I don't know what the difference would be from one project to the next that would cause this error. The test is a console application and the program is a winforms app.
What conditions would cause the default property of these collections to change?
Edit - Thank you for all of the answers that tell me how to loop through a dictionary. Those, answers, however, do not answer my question of why I can use an index in one project and not the other. Should I not be able to copy and paste the code from one .net project to another and have it work the same? And, no, option strict, is not the cause of the problem.
Edit - Attempt to reproduce what I'm seeing:
Create a new VB.NET Console Application using VS 2008
Copy and paste the following code into the module:
Imports System.Collections
Imports System.Collections.Generic
Module Module1
Public dtf As Dictionary(Of Double, String)
Public Sub BuildDictionary()
dtf = New Dictionary(Of Double, String)
dtf.Add(1.0, "1")
dtf.Add(0.0, "0")
End Sub
Public Sub Search()
For idx As Integer = 0 To dtf.Keys.Count - 1
If dtf.Keys(idx) = 0 Then
Exit Sub
End If
Next
End Sub
Sub Main()
End Sub
End Module
In the line in sub search that says "dtf.Keys(idx) = 0" place your cursor after the right parenthesis and backspace you should get a tooltip that says, "<Extension> ElementAtOrDefault(index as Integer) as Double - index: the zero based element of the index to retrieve.
I am not getting that in my other project. Even though it seem I have the same references and settings.
KeyCollection does not implement indexers like that, you must enumerate through the MyDictionary.Keys.
c#
foreach(double key in MyDictionary.Keys)
Console.Write( MyDictionary[ key ] )
vb
For Each key As Double in MyDictionary.Keys
Console.Write( MyDictionary( key )
Next key
Looping with a for(;i++;) wouldn't be the correct way of going through your hashtable (dictionary) since it is not an array it really has no concept of an array index (array[index])
I bet your real project had OPTION STRICT ON, as all projects should, and that your test project had it OFF. That's why you didn't get a compiler error in your test project.
EDIT: the poster says he has OPTION STRICT ON for both projects. That makes this more interesting.
I still think the most likely reason for this difference is that in one case, the compiler compiled the code and saw the error; but in the other case, the compiler didn't comile the code. Is this the same version of Visual Studio on the same machine at the same time? Same .NET Framework version in both cases?
Are these both the same type of project, for instance, are they both console applications? I ask because ASP.NET Web Site "projects" usually don't attempt to compile code until the code is called. If your test project were such a "project", and if you didn't actualy test the code (that is, if you didn't actually step into this code and see it work), then you might have assumed that the fact you could press F5 meant that all the code was compiled, when it wasn't.
My next thoughts would be to see if MyDictionary was really of the same type in both cases.
Beyond that, if you really need to know why this happened, I'd make a copy of the "real" project, and start changing it to be more and more like the test project. This would probably be a matter of mass deletions at first. I'd keep changing it either until the problem was found, or until the two were identical.
EDIT 2: The default console project imports the System.Linq namespace (see the "References" tab in project properties). This import brings the ElementAtOrDefault extension method into scope. This extension method extends IEnumerable(Of T); in your case IEnumerable(Of Double), which is what the Keys property implements.
What surprises me about this is that VB.NET is automatically applying this extension method. In C#, the method would need to be explicitly named.
If you remove the Import of System.Linq, you'll find that your test application gets the same error as the production application.
The Keys and Values property of Dictionary(Of TKey,TValue) do not have an indexer property. They are implementations of ICollection vs. IList and hence don't support accesses by Index. If you want to iterate through a Dictionary, the best way is a For Each loop.
For Each pair in MyDictionary
Dim key = pair.Key
Dim value = pair.Value
Next
EDIT
Have you checked to make sure that System.Core is referenced in both projects and that you have a project level imports for System.Linq? That's the only thing I can think of that would produce a difference in ElementAtOrDefault which is a method inside of system.Core.
I'm still a bit baffled why that method would be bound to for a simple indexer. Going to look into that