Click here to Skip to main content
15,881,281 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Below is the code I am using. I am trying to run this code with a button click event handler, but if I remove the static modifier the button click does nothing. If I have the static modifier the button click event handler cannot access GetClientCertificate(). I am not sure what to try next as it was working at one point several days ago and I am not sure what I changed. The button click event handler is at the bottom of the code.

C#
namespace TestSite
{
    public class CertSelect
    {

        public static X509Certificate2 GetClientCertificate()
        {
            IntPtr ptr = IntPtr.Zero;
            X509Certificate2 certificate = null;

            var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            try
            {
                store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
                
                if (store.Certificates != null && store.Certificates.Count > 0)
                {
                    if (store.Certificates.Count == 1)
                    {
                       
                        certificate = store.Certificates[0];
                    }
                    else
                    {
 
                        var certificates = X509Certificate2UI.SelectFromCollection(store.Certificates, "Digital Certificates", "Select a certificate from the following list:", X509SelectionFlag.SingleSelection, ptr);

                        if (certificates != null && certificates.Count > 0)
                            certificate = certificates[0];

                    }
                }
            }
            finally
            {
                store.Close();
            }

            return certificate;

        }
    }
}

Button click event handler:

C#
protected void CertLogin_Click(object sender, EventArgs e)
{

    CertSelect thumb = new CertSelect();
    thumb.GetClientCertificate();
}


What I have tried:

I tried to remove the static modifier, and tried to add a method above GetClientCertificate(). Not sure what to try next.
Posted
Updated 25-Jan-22 7:49am
v2

If it is a static method you should call it like this.

protected void CertLogin_Click(object sender, EventArgs e)
{
    CertSelect.GetClientCertificate();
}
 
Share this answer
 
Comments
Michaelred54 27-Jan-22 9:21am    
So this question was resolved with your answer and this code ran perfectly as intended. I added more code for the next step in this project and it did not work as intended so I decided to undo my changes and the code is now exactly like it was before but it does nothing when it runs. I get no errors but I am not prompted for a certificate to select. Is visual studio holding on to something compiled that might be messing with the code? This is not the first time something like this has happened.
Tony Hill 27-Jan-22 10:37am    
Have you stepped through the code using the debugger?.

Because I can see that just looking at the code at least one problem could occur, so unless you have more than one certificate in the store then the X509Certificate2UI.SelectFromCollection' code will not be executed and therefore you won't be asked.

There are other things in the code which might cause problems but the one I mentioned above is the one that sounds the most likely.
Michaelred54 27-Jan-22 10:44am    
I have stepped through the code with the debugger and it does not find any errors. I actually have 5 certificates in the store. I also tried to use chrome, IE, Edge, and Firefox but they all have the same result of nothing. When this was first fixed I ran it a dozen times and it worked every time. I simply added code at the top, ran it to see it didnt work like I wanted and undid my changes. now it acts like it finds nothing in the store so ends the program or finds only one and does not prompt me to select one.
Tony Hill 27-Jan-22 11:32am    
The first thing you should do is fix your try/finally block and put a catch handler in there so when an error occurs it is caught so that it is possible to view the exception data.

At the moment when an error occurs any where in the try block the final block is executed and the program ends without notifying you.

When you used the debugger did the store open successfully?

If the store opened successfully how many records did the store.Certificate.Count return?

The answer to these questions can only be found by stepping the code in the debugger.

Once you have answered these questions it might be possible to solve the problem.
Michaelred54 27-Jan-22 12:29pm    
I turned on debugging to step through every line of the code. the first time, it actually worked. the next time I ran it, I was prompted for the source location for x509utils.cs. since it cannot find this source file it fails and does nothing.

The debugger could not locate the source file 'f:\dd\NDP\fx\src\security\system\security\cryptography\x509\x509utils.cs'.
To add to Tony's solution, let me explain the difference between static and non-static objects.

C# is all about classes: everything is part of a class. But they aren't all the same. If you think of cars instead of computers for a moment, you already understand about classes and their instances: your car is a green Ford, my car is a black Mercedes, this car is a green Citroen. Each individual vehicle is an instance of the class "car" - and they are separate and different. If you repaint your car, that doesn't affect "this car" it remains a Green Citroen even if your car is now a Red Ford. These things are called "properties" and they transate exactly into C#.

When you declare a "normal method" it has access to all the fields, properties and methods that are part of the class and apply to an instance of that class.
C#
public class Car
   {
   public Color Colour;
   public void Repaint(Color newColour) { Colour = newColour; }
   }
Repaint accesses the properties of the current instance of the Car class and changes the colour of that vehicle only.

But ... there are also static methods (and fields, and properties) which are shared by all instances of a car: all cars have four wheels so it's pointless storing the number of wheels for each instance! But because the "CountWheels" method is generic to all Cars, it can't access any instance specific information as it has no idea which instance to get info from!

So to access "normal" methods, you prefix it with an instance:
C#
public class Car
   {
   public Color Colour;
   public void Repaint(Color newColour) { Colour = newColour; }
   }
...
Car myCar = new Car(Color.Black, Make.Mercedes);
Car yourCar = new Car(Color.Green, Make.Ford);
Car thisCar = new Car(Color.Green, Make.Citroen);
yourCar.Repaint(Color.Red);
...
To access a static method, you can't prefix it with an instance, because that would imply it had access to instance data. Instead you prefix it with the Class name
C#
public class Car
   {
   public Color Colour;
   public void Repaint(Color newColour) { Colour = newColour; }
   public static int NumberOfWheels = 4;
   }
...
Car myCar = new Car(Color.Black, Make.Mercedes);
Car yourCar = new Car(Color.Green, Make.Ford);
Car thisCar = new Car(Color.Green, Make.Citroen);
yourCar.Repaint(Color.Red);
Console.WriteLine(Car.NumberOfWheels);
...

Make sense?
 
Share this answer
 
Comments
Michaelred54 25-Jan-22 14:03pm    
Thank you. Your explanation makes sense and helps a lot and is exactly the 'type' of explanation I need to understand 'methods'. Thanks again for your time in putting this together.
OriginalGriff 25-Jan-22 16:07pm    
You're wwelcome!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900