2016-04-04 57 views
0

私はsignalrクライアントとchatseverをクラスとして実装してチャットアプリケーションを行っています。今私はwcfサービスとしてチャットサーバーを実装したい。シグナルアプリケーションをwcfサービスとして使用するチャットアプリケーション

<link rel="stylesheet" href="Styles/jquery-ui.css" /> 
    <script src="Scripts/jquery-1.8.2.js"></script> 
    <script src="Scripts/jquery-ui.js"></script> 
    <script type="text/javascript" src="Scripts/jquery.dialogextend.1_0_1.js"></script> 
    <script type="text/javascript" src="Scripts/jquery.signalR.js"></script> 
    <script type="text/javascript" src="Scripts/jQuery.tmpl.js"></script> 
    <script type="text/javascript" src="signalr/hubs"></script> 
    <script id="new-online-contacts" type="text/x-jquery-tmpl"> 
     <div> 
     <ul> 
     {{each messageRecipients}} 
      <li id="chatLink${messageRecipientId}"><a href="javascript:;" onclick="javascript:SRChat.initiateChat('${messageRecipientId}','${messageRecipientName}');">${messageRecipientName}</a></li> 
     {{/each}} 
     </ul> 
     </div> 
    </script> 
    <script id="new-chatroom-template" type="text/x-jquery-tmpl"> 
    <div id="chatRoom${chatRoomId}" class="chatRoom"> 
     <ul id="messages${chatRoomId}" class="chatMessages"> 
     </ul> 
     <form id="sendmessage${chatRoomId}" action="#"> 
      <input type="text" id="newmessage${chatRoomId}" class="chatNewMessage"/> 
      <div class="clear"></div> 
      <input type="button" id="chatsend${chatRoomId}" value="Send" class="chatSend" OnClick="javascript:SRChat.sendChatMessage('${chatRoomId}')" /> 
      <input type="button" id="chatend${chatRoomId}" value="End Chat" class="chatSend" OnClick="javascript:SRChat.endChat('${chatRoomId}')" /> 
     </form> 
    </div> 
    </script> 
    <script id="new-chat-header" type="text/x-jquery-tmpl"> 
    <div id="chatRoomHeader${chatRoomId}"> 
     {{each messageRecipients}} 
      {{if $index == 0}} 
       ${messageRecipientName} 
      {{else}} 
       , ${messageRecipientName} 
      {{/if}} 
     {{/each}} 
    <div> 
    </script> 
    <script id="new-message-template" type="text/x-jquery-tmpl"> 
    <li class="message" id="m-${chatMessageId}"> 
     <strong>${displayPrefix}</strong> 
     {{html messageText}} 
    </li> 
    </script> 
    <script id="new-notify-message-template" type="text/x-jquery-tmpl"> 
    <li class="message" id="m-${chatMessageId}"> 
     <strong>{{html messageText}}</strong> 
    </li> 
    </script> 
    <script type="text/javascript"> 
    //<![CDATA[ 

     $(document).ready(function() { 

      SRChat.attachEvents(); 
     }); 

     SRChat = new function() { 
      var Username = GetParameterValues('Username'); 
      function GetParameterValues(param) { 
       var url = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); 
       for (var i = 0; i < url.length; i++) { 
        var urlparam = url[i].split('='); 
        if (urlparam[0] == param) { 
         return urlparam[1]; 
        } 
       } 
      } 
      var chatRooms = 0; 
      var numRand = Username; 
      var senderId = numRand; 
      var senderName = 'User :' + numRand; 

      var sRChatServer; 

      window.onbeforeunload = function() { 
       if (chatRooms > 0) 
        return "All chat instances will be ended!"; 
      }; 

      this.attachEvents = function() { 
       $("#userNameLabel").html(senderName); 
       if ($.connection != null) { 
        jQuery.support.cors = true; 
        $.connection.hub.url = 'signalr/hubs'; 
        sRChatServer = $.connection.sRChatServer; 

        $.connection.hub.start({ transport: 'auto' }, function() { 
         sRChatServer.server.connect(senderId, senderName).fail(function (e) { 
          alert(e); 
         }); 
        }); 

        sRChatServer.client.initiateChatUI = function (chatRoom) { 
         var chatRoomDiv = $('#chatRoom' + chatRoom.chatRoomId); 
         if (($(chatRoomDiv).length > 0)) { 
          var chatRoomText = $('#newmessage' + chatRoom.chatRoomId); 
          var chatRoomSend = $('#chatsend' + chatRoom.chatRoomId); 
          var chatRoomEndChat = $('#chatend' + chatRoom.chatRoomId); 

          chatRoomText.show(); 
          chatRoomSend.show(); 
          chatRoomEndChat.show(); 
         } 
         else { 
          var e = $('#new-chatroom-template').tmpl(chatRoom); 
          var c = $('#new-chat-header').tmpl(chatRoom); 

          chatRooms++; 

          //dialog options 
          var dialogOptions = { 
           "id": '#messages' + chatRoom.chatRoomId, 
           "title": c, 
           "width": 360, 
           "height": 365, 
           "modal": false, 
           "resizable": false, 
           "close": function() { javascript: SRChat.endChat('' + chatRoom.chatRoomId + ''); $(this).remove(); } 
          }; 

          // dialog-extend options 
          var dialogExtendOptions = { 
           "close": true, 
           "maximize": false, 
           "minimize": true, 
           "dblclick": 'minimize', 
           "titlebar": 'transparent' 
          }; 

          e.dialog(dialogOptions).dialogExtend(dialogExtendOptions); 

          $('#sendmessage' + chatRoom.chatRoomId).keypress(function (e) { 
           if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) { 
            $('#chatsend' + chatRoom.chatRoomId).click(); 
            return false; 
           } 
          }); 
         } 
        }; 

        sRChatServer.client.updateChatUI = function (chatRoom) { 
         var chatRoomHeader = $('#chatRoomHeader' + chatRoom.chatRoomId); 
         var c = $('#new-chat-header').tmpl(chatRoom); 
         chatRoomHeader.html(c); 
        }; 

        sRChatServer.client.receiveChatMessage = function (chatMessage, chatRoom) { 
         sRChatServer.client.initiateChatUI(chatRoom); 
         var chatRoom = $('#chatRoom' + chatMessage.conversationId); 
         var chatRoomMessages = $('#messages' + chatMessage.conversationId); 
         var e = $('#new-message-template').tmpl(chatMessage).appendTo(chatRoomMessages); 
         e[0].scrollIntoView(); 
         chatRoom.scrollIntoView(); 
        }; 

        sRChatServer.client.receiveLeftChatMessage = function (chatMessage) { 
         var chatRoom = $('#chatRoom' + chatMessage.conversationId); 
         var chatRoomMessages = $('#messages' + chatMessage.conversationId); 
         var e = $('#new-notify-message-template').tmpl(chatMessage).appendTo(chatRoomMessages); 
         e[0].scrollIntoView(); 
         chatRoom.scrollIntoView(); 
        }; 

        sRChatServer.client.receiveEndChatMessage = function (chatMessage) { 
         var chatRoom = $('#chatRoom' + chatMessage.conversationId); 
         var chatRoomMessages = $('#messages' + chatMessage.conversationId); 
         var chatRoomText = $('#newmessage' + chatMessage.conversationId); 
         var chatRoomSend = $('#chatsend' + chatMessage.conversationId); 
         var chatRoomEndChat = $('#chatend' + chatMessage.conversationId); 

         chatRooms--; 

         var e = $('#new-notify-message-template').tmpl(chatMessage).appendTo(chatRoomMessages); 

         chatRoomText.hide(); 
         chatRoomSend.hide(); 
         chatRoomEndChat.hide(); 

         e[0].scrollIntoView(); 
         chatRoom.scrollIntoView(); 
        }; 

        sRChatServer.client.onGetOnlineContacts = function (chatUsers) { 
         var e = $('#new-online-contacts').tmpl(chatUsers); 
         var chatLink = $('#chatLink' + senderId); 
         e.find("#chatLink" + senderId).remove(); 
         $("#chatOnlineContacts").html(""); 
         $("#chatOnlineContacts").html(e); 
        }; 
       } 
      }; 

      this.sendChatMessage = function (chatRoomId) { 
       var chatRoomNewMessage = $('#newmessage' + chatRoomId); 

       if (chatRoomNewMessage.val() == null || chatRoomNewMessage.val() == "") 
        return; 

       var chatMessage = { 
        senderId: senderId, 
        senderName: senderName, 
        conversationId: chatRoomId, 
        messageText: chatRoomNewMessage.val() 
       }; 

       chatRoomNewMessage.val(''); 
       chatRoomNewMessage.focus(); 
       sRChatServer.server.sendChatMessage(chatMessage).fail(function (e) { 
        alert(e); 
       }); 

       return false; 
      }; 

      this.endChat = function (chatRoomId) { 
       var chatRoomNewMessage = $('#newmessage' + chatRoomId); 

       var chatMessage = { 
        senderId: senderId, 
        senderName: senderName, 
        conversationId: chatRoomId, 
        messageText: chatRoomNewMessage.val() 
       }; 
       chatRoomNewMessage.val(''); 
       chatRoomNewMessage.focus(); 
       sRChatServer.server.endChat(chatMessage).fail(function (e) { 
        //alert(e); 
       }); 
      }; 

      this.initiateChat = function (toUserId, toUserName) { 
       if (sRChatServer == null) { 
        alert("Problem in connecting to Chat Server. Please Contact Administrator!"); 
        return; 
       } 
       sRChatServer.server.initiateChat(senderId, senderName, toUserId, toUserName).fail(function (e) { 
        alert(e); 
       }); 
      }; 

     }; 
    //]]> 
    </script> 
</head> 
<body> 
    <form id="form1" runat="server"> 

    <div> 

     <div id="userNameLabel"> 
     </div> 
     <br /> 
     <br /> 
     <div id="chatRooms"> 
     </div> 
     <div id="chatOnlineContacts"> 
     </div> 
    </div> 
    </form> 
</body> 

私のサーバー側のコードは、私は、WCFサービスまたはWebサービスとしてこれを実装したい

using System; 
using System.Collections.Concurrent; 
using System.Linq; 
using System.Threading.Tasks; 
using SignalR.Hubs; 

namespace SRChat 
{ 
    [HubName("sRChatServer")] 
    public class SRChatServer:Hub 

    { 
     #region Private Variables 
     private static readonly ConcurrentDictionary<string, MessageRecipient> _chatUsers = new ConcurrentDictionary<string, MessageRecipient>(StringComparer.OrdinalIgnoreCase); 
     private static readonly ConcurrentDictionary<string, ChatRoom> _chatRooms = new ConcurrentDictionary<string, ChatRoom>(StringComparer.OrdinalIgnoreCase); 
     #endregion 

     #region Public Methods 

     public bool Connect(string userId, string userName) 
     { 
      try 
      { 
       if (string.IsNullOrEmpty(userId) | string.IsNullOrEmpty(userName)) 
       { 
        return false; 
       } 
       if (GetChatUserByUserId(userId) == null) 
       { 
        AddUser(userId, userName); 
       } 
       else 
       { 
        ModifyUser(userId, userName); 
       } 
       SendOnlineContacts(); 
       return true; 
      } 
      catch (Exception ex) 
      { 
       throw new InvalidOperationException("Problem in connecting to chat server!"); 
      } 
     } 
     public override Task Disconnect() 
     { 
      try 
      { 
       DeleteUser(Context.ConnectionId); 
       return null; 
      } 
      catch (Exception ex) 
      { 
       throw new InvalidOperationException("Problem in disconnecting from chat server!"); 
      } 
     } 
     public bool InitiateChat(string fromUserId, string fromUserName, string toUserId, string toUserName) 
     { 
      try 
      { 
       if (string.IsNullOrEmpty(fromUserId) || string.IsNullOrEmpty(fromUserName) || string.IsNullOrEmpty(toUserId) || string.IsNullOrEmpty(toUserName)) 
       { 
        return false; 
       } 

       var fromUser = GetChatUserByUserId(fromUserId); 
       var toUser = GetChatUserByUserId(toUserId); 

       if (fromUser != null && toUser != null) 
       { 
        if (!CheckIfRoomExists(fromUser, toUser)) 
        { 
         //Create New Chat Room 
         ChatRoom chatRoom = new ChatRoom(); 
         chatRoom.chatRoomInitiatedBy = fromUser.messageRecipientId; 
         chatRoom.chatRoomInitiatedTo = toUser.messageRecipientId; 

         chatRoom.messageRecipients.Add(fromUser); 
         chatRoom.messageRecipients.Add(toUser); 

         //create and save blank message to get new conversation id 
         ChatMessage chatMessage = new ChatMessage(); 
         chatMessage.messageText = "Chat Initiated"; 
         chatMessage.senderId = fromUser.messageRecipientId; 
         chatMessage.senderName = fromUser.messageRecipientName; 

         fromUser.chatRoomIds.Add(chatRoom.chatRoomId); 
         toUser.chatRoomIds.Add(chatRoom.chatRoomId); 

         //Create SignalR Group for this chat room and add users connection to it 
         Groups.Add(fromUser.connectionId, chatRoom.chatRoomId); 
         Groups.Add(toUser.connectionId, chatRoom.chatRoomId); 

         //Add Chat room object to collection 
         if (_chatRooms.TryAdd(chatRoom.chatRoomId, chatRoom)) 
         { 
          //Generate Client UI for this room 
          Clients[fromUser.connectionId].initiateChatUI(chatRoom); 
         } 
        } 
       } 
       return true; 
      } 
      catch (Exception ex) 
      { 
       throw new InvalidOperationException("Problem in starting chat!"); 
      } 
     } 
     public bool EndChat(ChatMessage chatMessage) 
     { 
      try 
      { 
       ChatRoom chatRoom; 
       if (_chatRooms.TryGetValue(chatMessage.conversationId, out chatRoom)) 
       { 
        if (_chatRooms[chatRoom.chatRoomId].chatRoomInitiatedBy == chatMessage.senderId) 
        { 
         chatMessage.messageText = string.Format("{0} left the chat. Chat Ended!", chatMessage.senderName); 
         if (_chatRooms.TryRemove(chatRoom.chatRoomId, out chatRoom)) 
         { 
          Clients[chatRoom.chatRoomId].receiveEndChatMessage(chatMessage); 
          foreach (MessageRecipient messageReceipient in chatRoom.messageRecipients) 
          { 
           if (messageReceipient.chatRoomIds.Contains(chatRoom.chatRoomId)) 
           { 
            messageReceipient.chatRoomIds.Remove(chatRoom.chatRoomId); 
            Groups.Remove(messageReceipient.connectionId, chatRoom.chatRoomId); 
           } 
          } 
         } 
        } 
        else 
        { 
         MessageRecipient messageRecipient = GetChatUserByUserId(chatMessage.senderId); 
         if (messageRecipient != null && messageRecipient.chatRoomIds.Contains(chatRoom.chatRoomId)) 
         { 
          chatRoom.messageRecipients.Remove(messageRecipient); 
          messageRecipient.chatRoomIds.Remove(chatRoom.chatRoomId); 
          if (chatRoom.messageRecipients.Count < 2) 
          { 
           chatMessage.messageText = string.Format("{0} left the chat. Chat Ended!", chatMessage.senderName); 
           if (_chatRooms.TryRemove(chatRoom.chatRoomId, out chatRoom)) 
           { 
            Clients[chatRoom.chatRoomId].receiveEndChatMessage(chatMessage); 
            foreach (MessageRecipient messageReceipient in chatRoom.messageRecipients) 
            { 
             if (messageReceipient.chatRoomIds.Contains(chatRoom.chatRoomId)) 
             { 
              messageReceipient.chatRoomIds.Remove(chatRoom.chatRoomId); 
              Groups.Remove(messageReceipient.connectionId, chatRoom.chatRoomId); 
             } 
            } 
           } 
          } 
          else 
          { 
           chatMessage.messageText = string.Format("{0} left the chat.", chatMessage.senderName); 
           Groups.Remove(messageRecipient.connectionId, chatRoom.chatRoomId); 
           Clients[messageRecipient.connectionId].receiveEndChatMessage(chatMessage); 
           Clients[chatRoom.chatRoomId].receiveLeftChatMessage(chatMessage); 
           Clients[chatRoom.chatRoomId].updateChatUI(chatRoom); 
          } 
         } 
        } 
       } 
       else 
       { 
        throw new InvalidOperationException("Problem in ending chat!"); 
       } 
       return true; 
      } 
      catch (Exception ex) 
      { 
       throw new InvalidOperationException("Problem in ending chat!"); 
      } 
     } 
     public bool SendChatMessage(ChatMessage chatMessage) 
     { 
      try 
      { 
       ChatRoom chatRoom; 
       if (_chatRooms.TryGetValue(chatMessage.conversationId, out chatRoom)) 
       { 
        chatMessage.chatMessageId = Guid.NewGuid().ToString(); 
        chatMessage.timestamp = DateTime.Now; 
        Clients[chatMessage.conversationId].receiveChatMessage(chatMessage, chatRoom); 
        return true; 
       } 
       else 
       { 
        throw new InvalidOperationException("Problem in sending message!"); 
       } 
      } 
      catch (Exception ex) 
      { 
       throw new InvalidOperationException("Problem in sending message!"); 
      } 
     } 
     private bool SendOnlineContacts() 
     { 
      try 
      { 
       OnlineContacts onlineContacts = new OnlineContacts(); 
       foreach (var item in _chatUsers) 
       { 
        onlineContacts.messageRecipients.Add(item.Value); 
       } 
       Clients.onGetOnlineContacts(onlineContacts); 
       return false; 
      } 
      catch (Exception ex) 
      { 
       throw new InvalidOperationException("Problem in getting contacts!"); 
      } 
     } 

     #endregion 

     #region Private Methods 

     private Boolean CheckIfRoomExists(MessageRecipient fromUser, MessageRecipient toUser) 
     { 
      foreach (string chatRoomId in fromUser.chatRoomIds) 
      { 
       Int32 count = (from mr in _chatRooms[chatRoomId].messageRecipients 
           where mr.messageRecipientId == toUser.messageRecipientId 
           select mr).Count(); 
       if (count > 0) 
       { 
        return true; 
       } 
      } 
      foreach (string chatRoomId in toUser.chatRoomIds) 
      { 
       Int32 count = (from mr in _chatRooms[chatRoomId].messageRecipients 
           where mr.messageRecipientId == fromUser.messageRecipientId 
           select mr).Count(); 
       if (count > 0) 
       { 
        return true; 
       } 
      } 
      return false; 
     } 
     private MessageRecipient AddUser(string userId, string userName) 
     { 
      var user = new MessageRecipient(); 
      user.messageRecipientId = userId; 
      user.messageRecipientName = userName; 
      user.connectionId = Context.ConnectionId; 
      _chatUsers[userId] = user; 
      return user; 
     } 
     private MessageRecipient ModifyUser(string userId, string userName) 
     { 
      var user = GetChatUserByUserId(userId); 
      user.messageRecipientName = userName; 
      user.connectionId = Context.ConnectionId; 
      _chatUsers[userId] = user; 
      return user; 
     } 
     private Boolean DeleteUser(string userId, string userName) 
     { 
      var user = GetChatUserByUserId(userId); 
      if (user != null && _chatUsers.ContainsKey(user.messageRecipientId)) 
      { 
       MessageRecipient messageRecipient; 
       return _chatUsers.TryRemove(user.messageRecipientId, out messageRecipient); 
      } 
      return false; 
     } 
     private Boolean DeleteUser(string connectionId) 
     { 
      var returnValue = false; 
      var user = GetChatUserByConnectionId(connectionId); 
      if (user != null && _chatUsers.ContainsKey(user.messageRecipientId)) 
      { 
       MessageRecipient messageRecipient; 
       returnValue = _chatUsers.TryRemove(user.messageRecipientId, out messageRecipient); 

       //remoave from all groups and chatrooms 
       foreach (string chatRoomId in messageRecipient.chatRoomIds) 
       { 
        _chatRooms[chatRoomId].messageRecipients.Remove(messageRecipient); 

        Groups.Remove(messageRecipient.connectionId, chatRoomId); 

        //notify user left chat 
        ChatMessage chatMessage = new ChatMessage(); 
        chatMessage.conversationId = chatRoomId; 
        chatMessage.senderId = messageRecipient.messageRecipientId; 
        chatMessage.senderName = messageRecipient.messageRecipientName; 
        if (_chatRooms[chatRoomId].chatRoomInitiatedBy == messageRecipient.messageRecipientId) 
        { 
         chatMessage.messageText = string.Format("{0} left the chat. Chat Ended!", messageRecipient.messageRecipientName); 
         ChatRoom chatRoom; 

         if (_chatRooms.TryRemove(chatRoomId, out chatRoom)) 
         { 
          foreach (MessageRecipient messageReceipient in chatRoom.messageRecipients) 
          { 
           if (messageReceipient.chatRoomIds.Contains(chatRoomId)) 
           { 
            messageReceipient.chatRoomIds.Remove(chatRoomId); 
           } 
          } 
          Clients[chatRoomId].receiveEndChatMessage(chatMessage); 
         } 
        } 
        else 
        { 
         if (_chatRooms[chatRoomId].messageRecipients.Count() < 2) 
         { 
          chatMessage.messageText = string.Format("{0} left the chat. Chat Ended!", messageRecipient.messageRecipientName); 
          ChatRoom chatRoom; 
          if (_chatRooms.TryRemove(chatRoomId, out chatRoom)) 
          { 
           foreach (MessageRecipient messageReceipient in chatRoom.messageRecipients) 
           { 
            if (messageReceipient.chatRoomIds.Contains(chatRoomId)) 
            { 
             messageReceipient.chatRoomIds.Remove(chatRoomId); 
            } 
           } 
           Clients[chatRoomId].receiveEndChatMessage(chatMessage); 
          } 
         } 
         else 
         { 
          chatMessage.messageText = string.Format("{0} left the chat.", messageRecipient.messageRecipientName); 
          Clients[chatRoomId].receiveLeftChatMessage(chatMessage); 
         } 
        } 
       } 
      } 
      return returnValue; 
     } 
     private MessageRecipient GetChatUserByUserId(string userId) 
     { 
      return _chatUsers.Values.FirstOrDefault(u => u.messageRecipientId == userId); 
     } 
     private MessageRecipient GetChatUserByConnectionId(string connectionId) 
     { 
      return _chatUsers.Values.FirstOrDefault(u => u.connectionId == connectionId); 
     } 

     #endregion 
    } 
} 

です。私は事前に助けてください

+0

あなたは何を達成しようとしていますか? WCFコンソールでHubをホストしたいですか? –

+0

こんにちは@Quentin Roger、私はコンソールではなくweb wcfサービスとして実装しようとしています。 –

+0

Web wcfサービスは、IIS/managedサービスまたは管理対象アプリケーションでホストすることができます。どのようにしてwcfをホストするのですか? –

答えて

0

私はそれを達成するための最良の方法は、Windows管理サービスを作成することだと思います。(つまり、呼び出しごとの設定でIISでホストされている場合、サービスの有効期間を制御できません。

だから、あなたは(それが唯一のアイデアだが、私はコードがそのように見えることができると思います)、新しいWindowsサービスを作成し、WCFサービスとsignalrの両方をホストする必要があります

public class HostWindowService : ServiceBase 
{ 
    public ServiceHost serviceHost = null; 
    public HostWindowService() 
    {  
     ServiceName = "WCFWindowsServiceSample"; 
    } 

    public static void Main() 
    { 
     ServiceBase.Run(new HostWindowService()); 
    } 

    protected override void OnStart(string[] args) 
    { 
     //host wcf service 
     if (serviceHost != null) 
     { 
      serviceHost.Close(); 
     }     
     serviceHost = new ServiceHost(typeof(WCFService));  
     serviceHost.Open(); 

     //host signalr 
     Task.Run(() => SignalRHost());     
    } 

    private void SignalRHost() 
    { 
     try 
     { 
      SignalR = WebApp.Start("http://localhost:8080"); 
     } 
     catch (TargetInvocationException) 
     { 
      WriteToConsole("A server is already running at " + "http://localhost:8080");   
      return; 
     }  
    } 

    class Startup 
    { 
     public void Configuration(IAppBuilder app) 
     { 
      app.UseCors(CorsOptions.AllowAll); 
      app.MapSignalR(); 
     } 
    }  

    protected override void OnStop() 
    { 
     if (serviceHost != null) 
     { 
      serviceHost.Close(); 
      serviceHost = null; 
     } 
    } 
} 

参考文献:How to: Host a WCF Service in a Managed Windows ServiceSelf-Hosting SignalR in a Windows Service

+0

こんにちは@Quentin Roger、私の要件は、ウィンドウとWebアプリケーションを開発している署名付きのクライアントであり、これらのクライアント間の同期は、WCFサービスとして実装されている、つまり、このwt uを介して可能です。 –

+0

こんにちは@Quentin Roger、助けてください、可能ですか? –

+0

こんにちは@Quentin Roger、私はそれに取り組んでいます助けてください –

関連する問題