.NET Web Api InvalidOperationException 访问全局对象

.NET Web Api InvalidOperationException accessing global Object

我想做什么:

我使用 WebApiApplication 来控制服务器上的音乐播放器(将其想象成一种民主的音乐播放器:我和我的室友都可以通过智能手机访问它并可以以相同的方式控制它)。

网络调用是这样的:

http://localhost:64199/api/Music?category=Ambient&action=play

http://localhost:64199/api/Music?category=Ambient&action=next

我的控制器是这样的:

public class MusicController : ApiController
{

    const string MUSICPATH = @"...\Songs";

    public HttpResponseMessage Get(string category, string action, string song = "", bool shuffle = false)
    {

        // DirMusicPlayer.Category = category;
        DirMediaPlayer dmp = DirMediaPlayer.getInstance(category);

        System.Diagnostics.Debug.WriteLine("Thread-ID (Ctrl): " + Thread.CurrentThread.ManagedThreadId);

        switch (action)
        {
            case "play":
                if (song.Equals(""))
                {
                    dmp.PlayAll();
                }
                else
                {
                    dmp.PlaySong(song);
                }
                break;
            case "stop":

                dmp.Stop();
                break;
            case "next":
                dmp.PlayNext();
                break;
            case "prev":
                dmp.PlayPrevious();
                break;
            case "shuffle":
                dmp.Shuffle = shuffle;
                break;
            default:
                break;
        }


        return Request.CreateResponse(HttpStatusCode.OK, "Playing");
    }

}

Player 是一个专门的 System.Windows.Media.MediaPlayer 并实现为 Singleton。它首先在 Global.asax 中实例化,以随机歌曲开始。

每当我之后尝试访问它时(通过网络调用),应用程序都会崩溃并出现 InvalidOperationException,因为它无法访问玩家 运行 所在的线程。

我已经弄清楚线程会发生什么:

  1. Thread-ID (AppStart): 1 // Global.asax-Thread
  2. 线程 ID (MediaPlayer):1
  3. Thread-ID (MusicController): 7 //线程池中的控制器实例
  4. Thread-ID (MediaPlayer): 7 // 崩溃,因为 Media-Player 实例属于线程 1

如您所见,我知道问题出在哪里,但由于我是 .NET 的新手,所以我不知道如何解决它。我需要一个类似全局唯一控制器的东西来控制播放器并由那些 ApiControllers 调用。

我希望这个问题以前没有人问过,我试着查了一下,但我不知道要搜索什么。

MediaPlayer 继承自 DispatcherObject,它声明:

Only the thread that the Dispatcher was created on may access the DispatcherObject directly. To access a DispatcherObject from a thread other than the thread the DispatcherObject was created on, call Invoke or BeginInvoke on the Dispatcher the DispatcherObject is associated with.

现在我没有可用的设置来测试它,我认为 MediaPlayer class 不是为在 Web 应用程序中使用而设计的,但您可以试试这个:

 dmp.Dispatcher.Invoke(() => dmp.PlayNext(); );

它将在正确的线程上调用 PlayNext 方法。如果那没有导致成功,恐怕你必须接受它是行不通的。