#StackBounty: #c# #.net #profiling #clr #clr-profiling-api ICorProfilerCallback::ClassUnloadStarted not called for a generic class, eve…

Bounty: 100

I’m currently debugging my company’s CLR profiler (over ASP.NET 4.7.3282.0, .NET framework 4.7.2), and seeing a scenario in which the CLR unloads a class, but the ClassUnloadStarted callback is not called.

In a nutshell, our profiler keeps track of loaded classes using the ClassLoadStarted, ClassLoadFinished and ClassUnloadStarted callbacks. At some point, the class gets unloaded (along with its relevant module), but the ClassUnloadStarted callback is not called for its ClassID. Therefore, we’re left with a stall ClassID, thinking that the class is still loaded. Later on, when we try to query that ClassID, the CLR unsurprisingly crashes (since it now points to junk memory).

My question:

  • Why is ClassUnloadStarted not called for my (generic) class?
  • Is this the expected behaviour of the CLR, or possibly a CLR/Profiling API bug?

I couldn’t find any documentation about this behaviour or any relevant ticket from Microsoft. No hints I could find in the CoreCLR code, too. Thanks in advance for any help!

The Detailed Scenario:

This is the class in question (IComparable(T) with T=ClassFromModuleFoo):

System/IComparable`1<ClassFromModuleFoo>

During the test, the issue manifests after some modules have been unloaded.
Here’s the exact load/unload callbacks flow, based on debug prints added:

  1. The class System/IComparable'1(ClassFromModuleFoo), of mscorlib, is loaded.
  2. Immediately afterwards, the class ClassFromModuleFoo, of the module Foo, is loaded into assembly #1.
  3. Module Foo finishes to load into assembly #1.
  4. Then, module Foo is loaded again into a different assembly, #2.
  5. The IComparable and ClassFromModuleFoo are loaded again, this time in assembly #2. Now there are two instances of each class: one in Foo loaded in assembly #1, and one in Foo loaded in assembly #2.
  6. Module Foo begins to unload from assembly #1.
  7. ClassUnloadStarted callback is called for ClassFromModuleFoo in assembly #1.
  8. Module Foo finished to unload from assembly #1.
  9. ClassUnloadStarted is not called for System/IComparable'1(ClassFromModuleFoo) of assembly #1 anytime later (even though its module unloaded and its ClassID points to now thrashed memory).

Some additional information:

  • The issue also reproduces with the latest .NET framework version, 4.8 preview.
  • I’ve disabled native images by adding COR_PRF_DISABLE_ALL_NGEN_IMAGES to the profiler event mask, thinking it may impact the ClassLoad* callbacks, but it didn’t made any difference. I verified that mscorlib.dll in indeed loaded instead of its native image.

Edit:

Thanks to my very smart colleague, I was able to reproduce the issue with a small example project, that simulates this scenario by loading and unloading of AppDomains. Here it is:
https://github.com/shaharv/dotnet/tree/master/testers/module-load-unload

The crash occurs for this class in the test, which is unloaded, and for which the CLR didn’t call the unload callback:

Loop/MyGenList`1<System/String>

Here’s the relevant code, which is loaded and unloaded a few times:

namespace Loop
{
    public class MyGenList<T>
    {
        public List<T> _tList;

        public MyGenList(List<T> tList)
        {
            _tList = tList;
        }
    }

    class MyGenericTest
    {
        public void TestFunc()
        {
            MyGenList<String> genList = new MyGenList<String>(new List<string> { "A", "B", "C" });

            try
            {
                throw new Exception();
            }
            catch (Exception)
            {

            }
        }
    }
}

At some point, the profiler crashes trying to query the ClassID of that class – thinking it’s still valid, since the unload callback was not called for it.

On a side note, I tried porting this example to .NET Core for investigating further, but couldn’t figure out how, since .NET Core doesn’t support secondary AppDomains (and I’m not very sure it supports on-demand assembly unloading in general).


Get this bounty!!!

#StackBounty: #c# #.net #visual-studio #editorconfig Formatting rule to have blank line between class member declarations

Bounty: 50

Micrsoft provides bunch of coding settings for EditorConfig
.NET coding convention settings for EditorConfig

But cannot find the way to create a rule, which will suggest developer to add empty line between class members declaration.

// "Bad" style
public class Order
{
    private readonly IRepository _repository;
    private readonly IPriceCalculator _priceCalculator;
    public Order(IRepository repository, IPriceCalculator priceCalculator)
    {
        _repostitory = repository;
        _priceCalculator = priceCalculator;
    }
    public CopyFrom(Order originalOrder)
    {
        // Create new order
    }
    public Cancel(Customer customer)
    {
        // Cancel order
    }
}

// Good style
public class Order
{
    private readonly IRepository _repository;

    private readonly IPriceCalculator _priceCalculator;

    public Order(IRepository repository, IPriceCalculator priceCalculator)
    {
        _repostitory = repository;
        _priceCalculator = priceCalculator;
    }

    public CopyFrom(Order originalOrder)
    {
        // Create new order
    }

    public Cancel(Customer customer)
    {
        // Cancel order
    }
}


Get this bounty!!!

#StackBounty: #.net #botframework #cortana-intelligence Get raw voice from speech- BotBuilder v4

Bounty: 50

Working on the Bot Builder, I’m looking for a solution where I could get the audio of the speaker who spoke to the bot as attachment. Is it possible? Following is my code.

     public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
     {
            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                // Get the conversation state from the turn context.
                var state = await _accessors.CounterState.GetAsync(turnContext, () => new CounterState());

                // Bump the turn count for this conversation.
                state.TurnCount++;

                // Set the property using the accessor.
                await _accessors.CounterState.SetAsync(turnContext, state);

                // Save the new turn count into the conversation state.
                await _accessors.ConversationState.SaveChangesAsync(turnContext);

                Activity activity = new Activity();
                activity.Text = turnContext.Activity.Text;
                activity.Speak = turnContext.Activity.Speak;
                await turnContext.SendActivityAsync(activity.Text,activity.Speak,"acceptingInput",cancellationToken);
            }
            else
            {
                await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected");
            }
    }


Get this bounty!!!

#StackBounty: #c# #.net #azure #botframework Bot Channels Registration SocketException – An existing connection was forcibly closed by …

Bounty: 50

I have an Azure Web App with ASP.NET REST API application to behave as service for Bot Channels Registration.

In this app, I have one endpoint

 public async Task<IHttpActionResult> Post(string userToken, string botName, [FromBody] Activity activity)

where I receive a message from the user, process it and send back.

When I trying to communicate back to the user (either with typing activity or with an actual answer)

private static async Task ShowTyping(Activity activity, ConnectorClient client)
{
    var typingResponse = new Activity
    {
        Conversation = activity.Conversation,
        From = activity.Recipient,
        Locale = activity.Locale,
        Recipient = activity.From,
        ReplyToId = activity.Id,
        Id = activity.Id,
        Type = "typing"
    };
    await client.Conversations.UpdateActivityAsync(typingResponse);
}

foreach (var reply in replies)
{
      Trace.TraceInformation($"[{userToken}:{botName}] Sending reply {reply.Id}:{reply.Text}");
      await client.Conversations.ReplyToActivityAsync(reply);
}

through REST API I receive HttpRequestException - An existing connection was forcibly closed by the remote host:

2019-01-22T15:49:54  PID[17864] Error       System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host    at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)    at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)   
--- End of inner exception stack trace ---    at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)    at System.Net.PooledStream.EndWrite(IAsyncResult asyncResult)    at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)    --- End of inner exception stack trace ---    at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)    at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)    --- End of inner exception stack trace ---    at Microsoft.Rest.RetryDelegatingHandler.<SendAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)    at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)    at Microsoft.Bot.Connector.Conversations.<UpdateActivityWithHttpMessagesAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)    at Microsoft.Bot.Connector.ConversationsExtensions.<UpdateActivityAsync>d__16.MoveNext()
--- End of stack trace from previous location where exception was thrown ---    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)    at ChatFirst.Channels.BotFramework.Controllers.WebhookController.<ShowTyping>d__5.MoveNext()

Everything works fine on emulator and doesn’t work at all in the web service.
I tried to implement REST API client by myself but got the same result.

What am I missing?


More information on the issue

  1. I use v4.2 Bot Framework packages

    <package id="Microsoft.Bot.Builder" version="4.2.0" targetFramework="net472" />
    <package id="Microsoft.Bot.Connector" version="4.2.0" targetFramework="net472" />
    <package id="Microsoft.Bot.Schema" version="4.2.0" targetFramework="net472" />

  2. Entire Post method, userToken and botName are my internal credentials
    /// <summary>
    ///     POST: api/v1/webhook/{userToken}/{botName}
    ///     Receive a message from a user and reply to it
    /// </summary>
    [HttpPost]
    [Route("api/v1/webhook/{userToken}/{botName}")]
    public async Task<IHttpActionResult> Post(string userToken, string botName, [FromBody] Activity activity)
    {
        try
        {
            if (activity.Type == ActivityTypes.Message)
            {
                Trace.TraceInformation($"[{userToken}:{botName}] Message from {activity.From.Id}");
                MicrosoftAppCredentials credentials = _channelGateway.GetCredentials(userToken, botName);
    
                if (credentials == null)
                    return Ok();
    
                var serviceUri = new Uri(activity.ServiceUrl);
                var client = new ConnectorClient(serviceUri, credentials);
    
                await ShowTyping(activity, client);
    
                IEnumerable<Activity> replies = await _coreTalkService.GetRepliesAsync(new BotToken(userToken, botName), activity);
    
                foreach (var reply in replies)
                {
                    Trace.TraceInformation($"[{userToken}:{botName}] Sending reply {reply.Id}:{reply.Text}");
                    await client.Conversations.ReplyToActivityAsync(reply);
                }
            }
            else
            {
                HandleSystemMessage(activity);
            }
    
            return Ok();
        }
        catch (Exception e)
        {
            Trace.TraceError(e.ToString());
            return InternalServerError(e);
        }
    }
    
  3. Bot Channels Registrations settings looks like this
    Settings screenshot

  4. If I reroute Bot Channel to the local instance on my dev PC through ngrok I receive the same errors.

  5. I reduced entire method to perform simple echo answer, but error still remains

public async Task<IHttpActionResult> Post(string userToken, string botName, [FromBody] Activity activity)
{
    Trace.TraceInformation($"[{userToken}:{botName}] Message from {activity.From.Id}");
    var client = new ConnectorClient(new Uri(activity.ServiceUrl), 
        new MicrosoftAppCredentials("<secret>", "<secret>"));
    var answer = activity.CreateReply(activity.Text, activity.Locale);
    await client.Conversations.ReplyToActivityAsync(answer);
    return Ok();
}
  1. activity.ServiceUrl is https://webchat.botframework.com/
  2. Error happens if message sent through webchat, i didn’t check another channels
    enter image description here


Get this bounty!!!