microsoft / botframework-sdk

Bot Framework provides the most comprehensive experience for building conversation applications.
MIT License
7.48k stars 2.44k forks source link

[Question] Multiple types were found that match the controller named 'messages'? #3898

Closed Gh0s7 closed 6 years ago

Gh0s7 commented 6 years ago

Bot Info

Issue Description

Bot works fine on localhost, however I get this exception in my analytics when I deploy it:

POST to PriceTrackerBot failed: POST to the bot's endpoint failed with HTTP status 500 POST to the bot's endpoint failed with HTTP status 500

I also found out that navigating to myboturl/api/messages returns an exception, that can be the source of the previous 500 error:

<Error>
    <Message>An error has occurred.</Message>
    <ExceptionMessage>
        Multiple types were found that match the controller named 'messages'. 
        This can happen if the route that services this request ('api/{controller}/{id}') found multiple controllers defined with the same name but differing namespaces, which is not supported.
        The request for 'messages' has found the following matching controllers:
            PriceTracker.Bot.Controllers.MessagesControllerPriceTrackerBot.MessagesController
    </ExceptionMessage>
    <ExceptionType>System.InvalidOperationException</ExceptionType>
    <StackTrace>   
        at System.Web.Http.Dispatcher.DefaultHttpControllerSelector.SelectController(HttpRequestMessage request)
        at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
    </StackTrace>
</Error>

Code Example

Here's my route config lines (not changed it from the one generated by the template.

// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
    "DefaultApi",
    "api/{controller}/{id}",
    new {id = RouteParameter.Optional}
);
EricDahlvang commented 6 years ago

Hi @Gh0s7

Please share your project, or at least the messages controller, so we can take a look.

The answers on this StackOverflow post might also be helpful: https://stackoverflow.com/questions/7842293/multiple-types-were-found-that-match-the-controller-named-home

Gh0s7 commented 6 years ago

Hi there and thanks for the reply. Here's my MessagesController (please note that I don't have any other controller in my solution):

using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using MyApp.Bot.Dialogs;
using Activity = Microsoft.Bot.Connector.Activity;

namespace MyApp.Bot.Controllers
{
    [BotAuthentication]
    public class MessagesController : ApiController
    {
        /// <summary>
        ///     POST: api/Messages
        ///     Receive a message from a user and reply to it
        /// </summary>
        public async Task<HttpResponseMessage> Post([FromBody] Activity activity)
        {
            Trace.TraceInformation($"{nameof(MessagesController)}.{nameof(Post)}: received new {activity.Type} [{activity.AsMessageActivity()?.Text}]");

            if (activity.Type == ActivityTypes.Message)
                await Conversation.SendAsync(activity, () => new RootDialog());
            else
                HandleSystemMessage(activity);
            var response = Request.CreateResponse(HttpStatusCode.OK);
            return response;
        }

        private async void HandleConversationUpdate(Activity message)
        {
            Trace.TraceInformation($"{nameof(MessagesController)}.{nameof(HandleConversationUpdate)}: redirecting to {nameof(RootDialog)} [{message.AsMessageActivity()?.Text}]");

            await Conversation.SendAsync(message, () => new RootDialog());
        }

        private void HandleSystemMessage(Activity message)
        {
            Trace.TraceInformation($"{nameof(MessagesController)}.{nameof(HandleSystemMessage)}: received new {message.Type} [{message.AsMessageActivity()?.Text}]");

            switch (message.Type)
            {
                case ActivityTypes.DeleteUserData:
                    // Implement user deletion here
                    // If we handle user deletion, return a real message
                    break;
                case ActivityTypes.ConversationUpdate:
                    // Handle conversation state changes, like members being added and removed
                    // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
                    // Not available in all channels

                    Trace.TraceInformation($"{nameof(MessagesController)}.{nameof(HandleSystemMessage)}: added new members {string.Join(",", message.MembersAdded.Select(m => m.Name))} [{message.AsMessageActivity()?.Text}]");

                    // Start conversation flow
                    if (message.MembersAdded.All(m => m.Name.ToLowerInvariant() != "bot"))
                        HandleConversationUpdate(message);
                    break;
                case ActivityTypes.ContactRelationUpdate:
                    // Handle add/remove from contact lists
                    // Activity.From + Activity.Action represent what happened

                    // Start conversation flow
                    HandleConversationUpdate(message);
                    break;
                case ActivityTypes.Typing:
                    // Handle knowing tha the user is typing
                    break;
                case ActivityTypes.Ping:
                    break;
            }

            return;
        }
    }
}

It's basically the one generated by the template with just some tracing and the redirect to my RootDialog. I already searched on StackOverflow but I think my situation is quite different from the others as I only have one controller and no weird things in my routes.

xjose97x commented 6 years ago

This had happened to me multiple times when deploying to Azure App Service (one click deployment from Visual Studio). I've never found a solution for it. What I've done is just delete that app service, and create a new one and deploy there.

Apparently this is an issue in App Services when you change a controller (I've noticed with namespace), it seems to cache(not sure if the right term, but it kinds of "remembers it") the old one, and then it doesn't know where to route your request, if to the route in the old namespace or to the new one.

A co-worker of mine suggested deleting some files (I believe are bin folders and dlls) through FTP, and then re-deploy. Have not tried this last one, but hope it works.

EricDahlvang commented 6 years ago

Hey @Gh0s7

Have you tried checking the "Remove additional files at destination" when you deploy?

image

Or, as mentioned by xjose97x, you can also delete the existing app files using ftp or https://YourAppName.scm.azurewebsites.net/DebugConsole/?shell=powershell before deploying.

Gh0s7 commented 6 years ago

Whoops, forgot this issue, sorry!

@xjose97x was right, I think I fixed it. Thanks also to @EricDahlvang ,I didn't knew about powershell support for bot apps.

wenrongwu commented 6 years ago

Thanks to EricDahlvang for the solution.

andavies commented 6 years ago

@xjose97x You just solved 2 hours of pain for me. I had renamed my project/solution/namespaces from the default "Microsoft.Bot.Samples...". Deleting the /bin folder solved it.

3tallah commented 5 years ago

Hey @Gh0s7

Have you tried checking the "Remove additional files at destination" when you deploy?

image

Or, as mentioned by xjose97x, you can also delete the existing app files using ftp or https://YourAppName.scm.azurewebsites.net/DebugConsole/?shell=powershell before deploying.

Thanks @EricDahlvang You saved my time 💯