0

I am following the answer here:

Calculating Bandwidth

And implemented everything like he said. My monitor is initialized like so:

netSentCounter.CategoryName = ".NET CLR Networking";
netSentCounter.CounterName = "Bytes Sent";
netSentCounter.InstanceName = Misc.GetInstanceName();
netSentCounter.ReadOnly = true;

I can corrently see that Misc.GetInstanceName() returns "MyProcessName[id]". However I keep getting the exception that the instance doesn't exist in the specified category.

My understanding is that the category for net sent/received isn't created until you actually send or receive.

I have added the app.config as described in the answer like so:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.net>
        <settings>
            <performanceCounters enabled="true" />
        </settings>
    </system.net>
</configuration>

Why do I still get an error?

Here is my monitoring code:

public static class Monitoring
{
    private static PerformanceCounter netSentCounter = new PerformanceCounter();

    //Static constructor
    static Monitoring()
    {
        netSentCounter.CategoryName = ".NET CLR Networking";
        netSentCounter.CounterName = "Bytes Sent";
        netSentCounter.InstanceName = Misc.GetInstanceName();
        netSentCounter.ReadOnly = true;
    }

    /// <summary>
    /// Returns the amount of data sent from the current application in MB
    /// </summary>
    /// <returns></returns>
    public static float getNetSent()
    {
        return (float)netSentCounter.NextValue() / 1048576; //Convert to from Bytes to MB
    }
}

And my Misc class:

public static class Misc
{

    //Returns an instance name
   internal static string GetInstanceName()
    {
        // Used Reflector to find the correct formatting:
        string assemblyName = GetAssemblyName();
        if ((assemblyName == null) || (assemblyName.Length == 0))
        {
            assemblyName = AppDomain.CurrentDomain.FriendlyName;
        }
        StringBuilder builder = new StringBuilder(assemblyName);
        for (int i = 0; i < builder.Length; i++)
        {
            switch (builder[i])
            {
                case '/':
                case '\\':
                case '#':
                    builder[i] = '_';
                    break;
                case '(':
                    builder[i] = '[';
                    break;

                case ')':
                    builder[i] = ']';
                    break;
            }
        }
        return string.Format(CultureInfo.CurrentCulture,
                             "{0}[{1}]",
                             builder.ToString(),
                             Process.GetCurrentProcess().Id);
    }

    /// <summary>
    /// Returns an assembly name
    /// </summary>
    /// <returns></returns>
    internal static string GetAssemblyName()
    {
        string str = null;
        Assembly entryAssembly = Assembly.GetEntryAssembly();
        if (entryAssembly != null)
        {
            AssemblyName name = entryAssembly.GetName();
            if (name != null)
            {
                str = name.Name;
            }
        }
        return str;
    }
 }

Edit: I have opened the resource monitor from windows to see what the problem is. The counter isn't being started albeit having the app.config set to do so.

Here is what i see (this before and after my application sending network activity)

enter image description here

And the name isn't what my method is returning. My method returns "SuperScraper[appId]" while in the resource it is called "Superscraper.vshost.exe".

So I have two problems now:

-My counter isn't starting on app startup -The name is differnet

Community
  • 1
  • 1
TheGateKeeper
  • 4,420
  • 19
  • 66
  • 101
  • can you show stacktrace? What is Misc? [Here](http://pastebin.com/f371375d6) is all code, just copy paste. – Renatas M. Apr 17 '12 at 09:36
  • Misc is just a library I use. I will post stack trace. – TheGateKeeper Apr 17 '12 at 09:40
  • 1
    The call stack is pretty much empty. All it does is call the method from my library. Is the problem because the code is on a library and not in my main application? My code is pretty much like yours. – TheGateKeeper Apr 17 '12 at 09:42
  • well I just relinked code from [this answer](http://stackoverflow.com/a/442459/754438). Is that Misc library written by you? How you reference it? – Renatas M. Apr 17 '12 at 09:48
  • I edited the code to show class names because it was a little confusing. From code I call `getNetSent()`. The static constructor calls `Misc` on the first run to get the assembly name. – TheGateKeeper Apr 17 '12 at 09:55
  • Take a look at [this question](http://stackoverflow.com/questions/8654104/performance-monitor-net-clr-networking-4-0-0-0-instance-naming) seems you have same InstanceName naming problem – Renatas M. Apr 17 '12 at 10:46
  • I have updated the main question with more details. – TheGateKeeper Apr 17 '12 at 12:13
  • I tried compiling the .cs file given `http://stackoverflow.com/questions/442409/c-bandwidth` just in case I did something wrong and it gives the same error. So I guess it is something that can't be fixed? – TheGateKeeper Apr 17 '12 at 12:21
  • I think you need to look at Performance Monitor not Resource Monitor. – Renatas M. Apr 17 '12 at 12:33
  • I was able to find my application under .Net CLR Networking but it only shows up after I send something. I will have a look at the other thread you linked because I seem to have the same naming problem. – TheGateKeeper Apr 17 '12 at 12:56
  • I posted what I tested in answer, maybe it helps you a bit. – Renatas M. Apr 17 '12 at 13:00

2 Answers2

4

Ok I have finally figured it out. The steps listed Calculating Bandwidth seem to be outdated and are no longer valid for .Net 4.

I am going to explain the whole process so you can do it aswell.

First off, you need to add this to your app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.net>
        <settings>
            <performanceCounters enabled="true" />
        </settings>
    </system.net>
</configuration>

Before .Net 4.0, this made the application create the counters on startup (and not for example, create the network counters when your application sends a request). In .Net 4.0, this tells it to create the counters when they are used. Ie. if you don't set this no counters will ever be created.

Now this is where I wasted most of my time. I was under the wrong assumption that if you create a performance counter with the same name that it would have had if it was created naturally, you would get the values. However all this does is block the real counter from showing up.

So doing this:

//In .Net 4.0 the category is called .NET CLR Networking 4.0.0.0 and not .NET CLR Networking
netSentCounter.CategoryName = ".NET CLR Networking 4.0.0.0";
netSentCounter.CounterName = "Bytes Sent";
netSentCounter.InstanceName = Misc.GetInstanceName();
netSentCounter.ReadOnly = false; //<==
netSentCounter.RawValue = 0;     //<==

Simply blocks the real counter.

What you need to do is start it up in a natural way. The best way to do this is to simply send a spoof request at application start, and then "listen" to the performance counter using:

//Send spoof request here
netSentCounter.CategoryName = ".NET CLR Networking 4.0.0.0";
netSentCounter.CounterName = "Bytes Sent";
netSentCounter.InstanceName = Misc.GetInstanceName();
netSentCounter.ReadOnly = true;

One final point. The instance name is no longer ApplicationName[appId]. Now it is:

[ApplicationName].exe_p[appId]_r[the CLR id hosting your application]_ad[ApplicationDomain]

Hope this saves someone time!!

Community
  • 1
  • 1
TheGateKeeper
  • 4,420
  • 19
  • 66
  • 101
  • Upvote for "In .Net 4.0, this tells it to create the counters when they are used". Thanks :) – Henners Nov 10 '14 at 12:21
  • 1
    By the way, here is the correct way of getting the full instance name for the .NET performance counters: http://stackoverflow.com/questions/10196432/getting-the-clr-id – Funbit Mar 06 '15 at 16:26
2

Ok I tried your example. I also expierenced that counter didnt showed in Performance Monitor, but it did after I changed ReadOnly and set RawValue properties:

netSentCounter.CategoryName = ".NET CLR Networking";
netSentCounter.CounterName = "Bytes Sent";
netSentCounter.InstanceName = Misc.GetInstanceName();
netSentCounter.ReadOnly = false; //<==
netSentCounter.RawValue = 0;     //<==

In my case I found that instance name in performance monitor is in this format: myapplicationname_pPID

So after I changed in your GetInstanceName method line

return string.Format(CultureInfo.CurrentCulture,
                         "{0}[{1}]",
                         builder.ToString(),
                         Process.GetCurrentProcess().Id);

to

return string.Format(CultureInfo.CurrentCulture,
                     "{0}_p{1}",                
                     builder.ToString().ToLower(), //<== dont miss ToLower()
                     Process.GetCurrentProcess().Id);

counter looks like started to work.

Here is reference how to add and remove counter instance

Also think about removing(netSentCounter.RemoveInstance()) counter after you finish to use it.

Renatas M.
  • 11,694
  • 1
  • 43
  • 62
  • I really don't know what is wrong with it. I have managed to create it using your code, but it never returns anything. All it does is give me back 0. If I don't create it myself, it does return values. You think it is because of `netSentCounter.RawValue = 0;`? Did yours return values? – TheGateKeeper Apr 17 '12 at 13:31
  • well I didnt tested that, I just tried to figure out why you getting error. – Renatas M. Apr 17 '12 at 14:06
  • The name matches and I am creating it in the same place, but the values never change. If I don't create it and let it be created on it's own (ie by sending a request for example) it does report values. Can you test if you get the same behaviour? – TheGateKeeper Apr 17 '12 at 16:30