├── .gitignore ├── Client └── CoreClient │ ├── .vs │ └── CoreClient │ │ └── v14 │ │ └── .suo │ ├── Assets │ ├── Chat.meta │ ├── Chat │ │ ├── ChatClient.cs │ │ ├── ChatClient.cs.meta │ │ ├── ChatDemo.cs │ │ ├── ChatDemo.cs.meta │ │ ├── ChatModel.cs │ │ └── ChatModel.cs.meta │ ├── Plugins.meta │ ├── Plugins │ │ ├── websocket-sharp.dll │ │ └── websocket-sharp.dll.meta │ ├── Score.meta │ ├── Score │ │ ├── ScoreDemo.cs │ │ ├── ScoreDemo.cs.meta │ │ ├── ScoreModel.cs │ │ └── ScoreModel.cs.meta │ ├── Utilities.meta │ ├── Utilities │ │ ├── MonoHelper.cs │ │ ├── MonoHelper.cs.meta │ │ ├── RestClient.cs │ │ ├── RestClient.cs.meta │ │ ├── RestClient.cs.old │ │ ├── RestClient.cs.old.meta │ │ ├── UnityWebRequestExt.cs │ │ └── UnityWebRequestExt.cs.meta │ ├── demo.unity │ └── demo.unity.meta │ ├── CoreClient.CSharp.csproj │ ├── CoreClient.sln │ └── ProjectSettings │ ├── AudioManager.asset │ ├── ClusterInputManager.asset │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── NavMeshAreas.asset │ ├── NetworkManager.asset │ ├── Physics2DSettings.asset │ ├── ProjectSettings.asset │ ├── ProjectVersion.txt │ ├── QualitySettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ ├── UnityAdsSettings.asset │ └── UnityConnectSettings.asset ├── README.md └── Server ├── .vs ├── CoreWeb1 │ └── v14 │ │ └── .suo ├── config │ └── applicationhost.config └── restore.dg ├── CoreWeb1.sln ├── global.json └── src └── CoreWeb1 ├── Controllers ├── ChatService.cs ├── HomeController.cs ├── ScoreController.cs └── ScoreController.cs.old ├── CoreWeb1.xproj ├── CoreWeb1.xproj.user ├── Data ├── ChatClient.cs ├── ScoreContext.cs └── ScoreModel.cs ├── Dockerfile ├── Infrastructure ├── AsyncLock │ ├── AsyncLock.cs │ └── AsyncSemaphore.cs └── ModuleViewLocator.cs ├── Program.cs ├── Properties ├── Docker.props ├── Docker.targets └── launchSettings.json ├── Startup.cs ├── Views └── Home │ └── Index.cshtml ├── appsettings.json ├── project.json ├── project.lock.json └── web.config /.gitignore: -------------------------------------------------------------------------------- 1 | Client/CoreClient/Temp/ 2 | Client/CoreClient/Library/ 3 | Library 4 | Temp 5 | *.userprefs 6 | Server/src/CoreWeb1/obj/ 7 | Server/src/CoreWeb1/bin/ 8 | -------------------------------------------------------------------------------- /Client/CoreClient/.vs/CoreClient/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/.vs/CoreClient/v14/.suo -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Chat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb1ce3100631587429e2c5c44a008364 3 | folderAsset: yes 4 | timeCreated: 1465600672 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Chat/ChatClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using WebSocketSharp; 4 | 5 | namespace Chat 6 | { 7 | /// 8 | /// Wrapps the socket with strong typing 9 | /// 10 | public class ChatClient 11 | { 12 | public event Action OnChat = delegate { }; 13 | 14 | public event Action OnOpen = delegate { }; 15 | 16 | public event Action OnClose = delegate { }; 17 | 18 | // 19 | 20 | private WebSocket _socket; 21 | 22 | // 23 | 24 | public void Open(string url) 25 | { 26 | Close(); 27 | 28 | _socket = new WebSocket(url); 29 | 30 | _socket.OnOpen += _socket_OnOpen; 31 | _socket.OnClose += _socket_OnClose; 32 | _socket.OnMessage += _socket_OnMessage; 33 | _socket.OnError += _socket_OnError; 34 | 35 | _socket.Connect(); 36 | } 37 | 38 | public void Close() 39 | { 40 | if (_socket != null) 41 | { 42 | _socket.OnOpen -= _socket_OnOpen; 43 | _socket.OnClose -= _socket_OnClose; 44 | _socket.OnMessage -= _socket_OnMessage; 45 | _socket.OnError -= _socket_OnError; 46 | 47 | _socket.Close(); 48 | _socket = null; 49 | OnClose(); 50 | } 51 | } 52 | 53 | public void Send(ChatModel model) 54 | { 55 | if (_socket != null) 56 | _socket.Send(JsonUtility.ToJson(model)); 57 | } 58 | 59 | // 60 | 61 | private void _socket_OnError(object sender, ErrorEventArgs e) 62 | { 63 | MonoHelper.InvokeOnMainThread(() => 64 | { 65 | Debug.LogException(e.Exception); 66 | }); 67 | } 68 | 69 | private void _socket_OnMessage(object sender, MessageEventArgs e) 70 | { 71 | MonoHelper.InvokeOnMainThread(() => 72 | { 73 | ChatModel model = JsonUtility.FromJson(e.Data); 74 | OnChat(model); 75 | }); 76 | } 77 | 78 | private void _socket_OnClose(object sender, CloseEventArgs e) 79 | { 80 | MonoHelper.InvokeOnMainThread(OnClose); 81 | } 82 | 83 | private void _socket_OnOpen(object sender, EventArgs e) 84 | { 85 | MonoHelper.InvokeOnMainThread(OnOpen); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Chat/ChatClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 047b2691fdf6f4e48abd0814878ba964 3 | timeCreated: 1465607649 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Chat/ChatDemo.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Chat 4 | { 5 | public class ChatDemo : MonoBehaviour 6 | { 7 | public string ServerPath = "ws://localhost:58459/"; 8 | 9 | public ChatClient _client; 10 | 11 | public string UserName = "NICK"; 12 | public string Message = "HELLO WORLD"; 13 | 14 | 15 | void OnDestroy() 16 | { 17 | if (_client != null) 18 | { 19 | _client.Close(); 20 | _client.OnClose -= _client_OnClose; 21 | _client.OnOpen -= _client_OnOpen; 22 | _client.OnChat -= _client_OnChat; 23 | _client = null; 24 | } 25 | } 26 | 27 | 28 | private void _client_OnChat(ChatModel obj) 29 | { 30 | Debug.Log(obj.UserName + " : " + obj.Message); 31 | } 32 | 33 | private void _client_OnOpen() 34 | { 35 | Debug.Log("Chat is open"); 36 | } 37 | 38 | private void _client_OnClose() 39 | { 40 | Debug.Log("Chat is closed"); 41 | } 42 | 43 | [ContextMenu("Open")] 44 | public void Open() 45 | { 46 | OnDestroy(); 47 | _client = new ChatClient(); 48 | _client.OnClose += _client_OnClose; 49 | _client.OnOpen += _client_OnOpen; 50 | _client.OnChat += _client_OnChat; 51 | _client.Open(ServerPath); 52 | } 53 | 54 | [ContextMenu("Close")] 55 | public void Close() 56 | { 57 | OnDestroy(); 58 | } 59 | 60 | [ContextMenu("Send")] 61 | public void Send() 62 | { 63 | _client.Send(new ChatModel 64 | { 65 | Message = Message, 66 | UserName = UserName 67 | }); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Chat/ChatDemo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 054103fef71e3fc42b5638ef921897fd 3 | timeCreated: 1465601344 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Chat/ChatModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Chat 5 | { 6 | // TODO Move this to a DLL exported by a shared data project 7 | // This is not avaliable yet in dotnetcore 8 | 9 | /// 10 | /// Our DTO 11 | /// 12 | [Serializable] 13 | public class ChatModel 14 | { 15 | [SerializeField] 16 | public string UserName; 17 | [SerializeField] 18 | public string Message; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Chat/ChatModel.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da6bd912e81ecad4e9bec5e3f4fe3f9b 3 | timeCreated: 1465600672 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8a737d052183acb47af6da99b63a776a 3 | folderAsset: yes 4 | timeCreated: 1465599824 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Plugins/websocket-sharp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/Assets/Plugins/websocket-sharp.dll -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Plugins/websocket-sharp.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1631427e51936d949b4dd5fbc62874eb 3 | timeCreated: 1465599832 4 | licenseType: Free 5 | PluginImporter: 6 | serializedVersion: 1 7 | iconMap: {} 8 | executionOrder: {} 9 | isPreloaded: 0 10 | platformData: 11 | Any: 12 | enabled: 1 13 | settings: {} 14 | Editor: 15 | enabled: 0 16 | settings: 17 | DefaultValueInitialized: true 18 | WindowsStoreApps: 19 | enabled: 0 20 | settings: 21 | CPU: AnyCPU 22 | userData: 23 | assetBundleName: 24 | assetBundleVariant: 25 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Score.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2725bc579684f664085e513726eeee6c 3 | folderAsset: yes 4 | timeCreated: 1465600672 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Score/ScoreDemo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityEngine; 3 | 4 | namespace Score 5 | { 6 | // Really a View 7 | public class ScoreDemo : MonoBehaviour 8 | { 9 | public string ServerPath = "http://localhost:58459/api/Score"; 10 | 11 | public string UserName; 12 | public int Points; 13 | 14 | [ContextMenu("Get All Scores")] 15 | public void GetScores() 16 | { 17 | StartCoroutine(GetAllAsync()); 18 | } 19 | 20 | [ContextMenu("Get Score")] 21 | public void GetScore() 22 | { 23 | StartCoroutine(GetScoreAsync()); 24 | } 25 | 26 | [ContextMenu("Post My Scores")] 27 | public void PostScore() 28 | { 29 | StartCoroutine(PostScoreAsync()); 30 | } 31 | 32 | [ContextMenu("Delete My Scores")] 33 | public void DeleteScore() 34 | { 35 | StartCoroutine(DeleteScoreAsync()); 36 | } 37 | 38 | IEnumerator GetAllAsync() 39 | { 40 | Debug.Log("GetAllAsync..."); 41 | yield return 1; 42 | 43 | var task = RestClient.Get(ServerPath); 44 | 45 | yield return task.Send(); 46 | 47 | if (task.isError) 48 | { 49 | Debug.LogError(task.error); 50 | } 51 | else 52 | { 53 | var scores = task.Deserialize(); 54 | 55 | if (scores == null || scores.Scores == null) 56 | Debug.Log("Not Found"); 57 | else 58 | { 59 | Debug.Log("Success !"); 60 | foreach (var score in scores.Scores) 61 | { 62 | Debug.Log(score.UserName + " " + score.Points); 63 | } 64 | } 65 | } 66 | 67 | task.Dispose(); 68 | } 69 | 70 | IEnumerator GetScoreAsync() 71 | { 72 | 73 | Debug.Log("GetScoreAsync..."); 74 | yield return 1; 75 | 76 | 77 | var task = RestClient.Get(ServerPath, UserName); 78 | 79 | //start the task and wait for it to complete 80 | yield return task.Send(); 81 | 82 | if (task.isError) 83 | { 84 | Debug.LogError(task.error); 85 | } 86 | else 87 | { 88 | var score = task.Deserialize(); 89 | if(score == null) 90 | Debug.Log("NotFound"); 91 | else 92 | Debug.Log(score.UserName + " " + score.Points); 93 | } 94 | 95 | task.Dispose(); 96 | } 97 | 98 | IEnumerator PostScoreAsync() 99 | { 100 | Debug.Log("PostScoreAsync..."); 101 | yield return 1; 102 | 103 | var model = new ScoreModel 104 | { 105 | UserName = UserName, 106 | Points = Points, 107 | }; 108 | 109 | var json = JsonUtility.ToJson(model); 110 | 111 | var task = RestClient.Post(ServerPath, json); 112 | 113 | yield return task.Send(); 114 | 115 | if (task.isError) 116 | { 117 | Debug.LogError(task.error); 118 | } 119 | else 120 | { 121 | Debug.Log("Success"); 122 | } 123 | 124 | task.Dispose(); 125 | } 126 | 127 | IEnumerator DeleteScoreAsync() 128 | { 129 | Debug.Log("DeleteScoreAsync..."); 130 | yield return 1; 131 | 132 | var task = RestClient.Delete(ServerPath, UserName); 133 | 134 | yield return task.Send(); 135 | 136 | if (task.isError) 137 | { 138 | Debug.LogError(task.error); 139 | } 140 | else 141 | { 142 | Debug.Log("Success"); 143 | } 144 | 145 | task.Dispose(); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Score/ScoreDemo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: de9a90fcb633e8c499a3cbc4d2368b31 3 | timeCreated: 1465600672 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Score/ScoreModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Score 5 | { 6 | /// 7 | /// Client side data model. 8 | /// This can be shared...... 9 | /// 10 | [Serializable] 11 | public class ScoreModel 12 | { 13 | [SerializeField] 14 | public string UserName; 15 | [SerializeField] 16 | public int Points; 17 | } 18 | 19 | /// 20 | /// Client side data model. 21 | /// This can be shared...... 22 | /// 23 | [Serializable] 24 | public class ScoreModelContainer 25 | { 26 | public ScoreModel[] Scores; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Score/ScoreModel.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3dd720dbe7aa5c4488f6d6c1ed7e00a6 3 | timeCreated: 1465600672 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eecc27684ad794b44a648220dc48ac87 3 | folderAsset: yes 4 | timeCreated: 1465517486 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities/MonoHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | 6 | /// 7 | /// Helper for accessing Unity methods from CLR objects 8 | /// 9 | public class MonoHelper : MonoBehaviour 10 | { 11 | 12 | private static MonoHelper _instance; 13 | public static MonoHelper Instance 14 | { 15 | get 16 | { 17 | EnsureInitialized(); 18 | return _instance; 19 | } 20 | } 21 | 22 | static void EnsureInitialized() 23 | { 24 | if (_instance == null) 25 | { 26 | var go = new GameObject("_MonoHelper"); 27 | DontDestroyOnLoad(go); 28 | _instance = go.AddComponent(); 29 | } 30 | } 31 | 32 | 33 | #region Invoke on main 34 | static Queue _pendingActions = new Queue(); 35 | static object _lock = new object(); 36 | 37 | /// 38 | /// Registers an action to invoke on the main thread 39 | /// 40 | /// the action to call 41 | public static void InvokeOnMainThread(Action func) 42 | { 43 | EnsureInitialized(); 44 | 45 | lock (_lock) 46 | { 47 | _pendingActions.Enqueue(func); 48 | } 49 | } 50 | 51 | 52 | void Update() 53 | { 54 | if(!_pendingActions.Any()) 55 | return; 56 | 57 | lock (_lock) 58 | { 59 | while (_pendingActions.Any()) 60 | { 61 | var action = _pendingActions.Dequeue(); 62 | 63 | action(); 64 | } 65 | } 66 | } 67 | 68 | 69 | #endregion 70 | } 71 | 72 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities/MonoHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 86768687a37daad4fafd2e8311d33a1a 3 | timeCreated: 1465516330 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities/RestClient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine.Networking; 3 | 4 | /// 5 | /// Wraps WWW to conform to API Routing conventions. 6 | /// Extensibility point for things like Authentication. 7 | /// 8 | /// 9 | /// Using WWW and name convention instead of HTTP verbs due to WWW limitation. 10 | /// Not useing UnityWebRequest due to it not working. 11 | /// 12 | /// 13 | public class RestClient 14 | { 15 | /// 16 | /// Global Headers (Authentication and such) 17 | /// 18 | public static Dictionary Headers = new Dictionary(); 19 | 20 | static RestClient() 21 | { 22 | Headers.Add("CONTENT-TYPE", "application/json"); 23 | Headers.Add("ACCEPT", "application/json"); 24 | } 25 | 26 | static void ApplyHeaders(UnityWebRequest task) 27 | { 28 | foreach (var header in Headers) 29 | { 30 | task.SetRequestHeader(header.Key, header.Value); 31 | } 32 | } 33 | 34 | public static UnityWebRequest Get(string url) 35 | { 36 | var task = UnityWebRequest.Get(url); 37 | ApplyHeaders(task); 38 | return task; 39 | } 40 | 41 | public static UnityWebRequest Get(string url, string id) 42 | { 43 | if (!url.EndsWith("/")) 44 | url += "/"; 45 | 46 | url += id; 47 | 48 | var task = UnityWebRequest.Get(url); 49 | ApplyHeaders(task); 50 | return task; 51 | } 52 | 53 | public static UnityWebRequest Post(string url) 54 | { 55 | var task = UnityWebRequest.Post(url, string.Empty); 56 | ApplyHeaders(task); 57 | return task; 58 | } 59 | 60 | public static UnityWebRequest Post(string url, string payload) 61 | { 62 | UnityWebRequest task = new UnityWebRequest(url, "POST"); 63 | task.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(payload)); 64 | task.uploadHandler.contentType = "application/json"; 65 | task.downloadHandler = new DownloadHandlerBuffer(); 66 | ApplyHeaders(task); 67 | return task; 68 | // Media type wrong by default. 69 | //var task = UnityWebRequest.Post(url, payload); 70 | //ApplyHeaders(task); 71 | //return task; 72 | } 73 | 74 | public static UnityWebRequest Delete(string url, string id) 75 | { 76 | var task = UnityWebRequest.Delete(url); 77 | ApplyHeaders(task); 78 | return task; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities/RestClient.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: faf67dc474c55a64eac66e77d5c614be 3 | timeCreated: 1465516330 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities/RestClient.cs.old: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using UnityEngine.Experimental.Networking; 4 | 5 | /// 6 | /// Wraps WebRequests to conform to API Routing conventions. 7 | /// Extensibility point for things like Authentication. 8 | /// Http Client which fixes bugs in UnityWebRequest. 9 | /// 10 | /// 11 | public class RestClient 12 | { 13 | /// 14 | /// Http://{domain}/api/{controller} 15 | /// 16 | public string UrlBase; 17 | 18 | //TODO Add a static dictionary for headers (e.g. Authentication) 19 | //TODO Add WWW alternative (because UnityWebRequest breaks sometimes) 20 | 21 | public RestClient(string urlBase) 22 | { 23 | UrlBase = urlBase; 24 | } 25 | 26 | public UnityWebRequest Get() 27 | { 28 | UnityWebRequest task = new UnityWebRequest(UrlBase); 29 | task.downloadHandler = new DownloadHandlerBuffer(); 30 | task.method = UnityWebRequest.kHttpVerbGET; 31 | task.Send(); 32 | return task; 33 | } 34 | 35 | public UnityWebRequest Get(string id) 36 | { 37 | UnityWebRequest task = new UnityWebRequest(string.Format("{0}/{1}", UrlBase, id)); 38 | task.downloadHandler = new DownloadHandlerBuffer(); 39 | task.method = UnityWebRequest.kHttpVerbGET; 40 | return task; 41 | } 42 | 43 | public UnityWebRequest Post() 44 | { 45 | UnityWebRequest task = new UnityWebRequest(UrlBase); 46 | task.downloadHandler = new DownloadHandlerBuffer(); 47 | task.method = UnityWebRequest.kHttpVerbPOST; 48 | return task; 49 | } 50 | 51 | public UnityWebRequest Post(string payload) 52 | { 53 | UnityWebRequest task = new UnityWebRequest(UrlBase); 54 | task.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(payload)); 55 | task.downloadHandler = new DownloadHandlerBuffer(); 56 | task.method = UnityWebRequest.kHttpVerbPOST; 57 | return task; 58 | } 59 | 60 | public UnityWebRequest Delete(string id) 61 | { 62 | UnityWebRequest task = new UnityWebRequest(string.Format("{0}/{1}", UrlBase, id)); 63 | task.downloadHandler = new DownloadHandlerBuffer(); 64 | task.method = UnityWebRequest.kHttpVerbDELETE; 65 | return task; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities/RestClient.cs.old.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b126828a36a06484bba9aea58e501c3c 3 | timeCreated: 1465848724 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities/UnityWebRequestExt.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.Networking; 3 | 4 | public static class UnityWebRequestExt 5 | { 6 | ///Deserialize payload text as json 7 | public static T Deserialize(this UnityWebRequest handler) 8 | { 9 | if (string.IsNullOrEmpty(handler.downloadHandler.text)) 10 | return default(T); 11 | 12 | return JsonUtility.FromJson(handler.downloadHandler.text); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/Utilities/UnityWebRequestExt.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 342662410b957684dbddfe103bc9e2fb 3 | timeCreated: 1465517486 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Client/CoreClient/Assets/demo.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/Assets/demo.unity -------------------------------------------------------------------------------- /Client/CoreClient/Assets/demo.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 10d1533abb70d7e48b805fc6a74049d1 3 | timeCreated: 1465595505 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Client/CoreClient/CoreClient.CSharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 10.0.20506 7 | 2.0 8 | {FD4BD8E8-6E3B-A815-CD9D-D334C7FEFC1F} 9 | Library 10 | Assembly-CSharp 11 | 512 12 | {E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 13 | .NETFramework 14 | v3.5 15 | Unity Subset v3.5 16 | 17 | 18 | Game:1 19 | StandaloneWindows:5 20 | 5.3.5f1 21 | 22 | 23 | 4 24 | 25 | 26 | pdbonly 27 | false 28 | Temp\UnityVS_bin\Debug\ 29 | Temp\UnityVS_obj\Debug\ 30 | prompt 31 | 4 32 | DEBUG;TRACE;UNITY_5_3_OR_NEWER;UNITY_5_3_5;UNITY_5_3;UNITY_5;ENABLE_NEW_BUGREPORTER;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_DUCK_TYPING;ENABLE_FRAME_DEBUGGER;ENABLE_GENERICS;ENABLE_HOME_SCREEN;ENABLE_IMAGEEFFECTS;ENABLE_LIGHT_PROBES_LEGACY;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_PLUGIN_INSPECTOR;ENABLE_SHADOWS;ENABLE_SINGLE_INSTANCE_BUILD_SETTING;ENABLE_SPRITERENDERER_FLIPPING;ENABLE_SPRITES;ENABLE_SPRITE_POLYGON;ENABLE_TERRAIN;ENABLE_RAKNET;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_HUB;ENABLE_CLOUD_PROJECT_ID;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_METRICS;ENABLE_EDITOR_METRICS_CACHING;INCLUDE_DYNAMIC_GI;INCLUDE_GI;INCLUDE_IL2CPP;INCLUDE_DIRECTX12;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_LOCALIZATION;ENABLE_ANDROID_ATLAS_ETC1_COMPRESSION;ENABLE_EDITOR_TESTS_RUNNER;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_SUBSTANCE;ENABLE_TEXTUREID_MAP;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_LOG_MIXED_STACKTRACE;ENABLE_UNITYWEBREQUEST;ENABLE_EVENT_QUEUE;ENABLE_CLUSTERINPUT;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN 33 | false 34 | 35 | 36 | pdbonly 37 | false 38 | Temp\UnityVS_bin\Release\ 39 | Temp\UnityVS_obj\Release\ 40 | prompt 41 | 4 42 | TRACE;UNITY_5_3_OR_NEWER;UNITY_5_3_5;UNITY_5_3;UNITY_5;ENABLE_NEW_BUGREPORTER;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_DUCK_TYPING;ENABLE_FRAME_DEBUGGER;ENABLE_GENERICS;ENABLE_HOME_SCREEN;ENABLE_IMAGEEFFECTS;ENABLE_LIGHT_PROBES_LEGACY;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_PLUGIN_INSPECTOR;ENABLE_SHADOWS;ENABLE_SINGLE_INSTANCE_BUILD_SETTING;ENABLE_SPRITERENDERER_FLIPPING;ENABLE_SPRITES;ENABLE_SPRITE_POLYGON;ENABLE_TERRAIN;ENABLE_RAKNET;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_HUB;ENABLE_CLOUD_PROJECT_ID;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_METRICS;ENABLE_EDITOR_METRICS_CACHING;INCLUDE_DYNAMIC_GI;INCLUDE_GI;INCLUDE_IL2CPP;INCLUDE_DIRECTX12;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_LOCALIZATION;ENABLE_ANDROID_ATLAS_ETC1_COMPRESSION;ENABLE_EDITOR_TESTS_RUNNER;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_SUBSTANCE;ENABLE_TEXTUREID_MAP;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_LOG_MIXED_STACKTRACE;ENABLE_UNITYWEBREQUEST;ENABLE_EVENT_QUEUE;ENABLE_CLUSTERINPUT;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN 43 | false 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Library\UnityAssemblies\UnityEngine.dll 56 | 57 | 58 | Library\UnityAssemblies\UnityEngine.UI.dll 59 | 60 | 61 | Library\UnityAssemblies\UnityEngine.Networking.dll 62 | 63 | 64 | Library\UnityAssemblies\UnityEngine.Networking.dll 65 | 66 | 67 | Library\UnityAssemblies\UnityEngine.UI.dll 68 | 69 | 70 | Library\UnityAssemblies\UnityEditor.dll 71 | 72 | 73 | Library\UnityAssemblies\Mono.Cecil.dll 74 | 75 | 76 | Library\UnityAssemblies\UnityEditor.iOS.Extensions.Xcode.dll 77 | 78 | 79 | Library\UnityAssemblies\UnityEditor.iOS.Extensions.Common.dll 80 | 81 | 82 | Assets\Plugins\websocket-sharp.dll 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /Client/CoreClient/CoreClient.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2015 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreClient.CSharp", "CoreClient.CSharp.csproj", "{FD4BD8E8-6E3B-A815-CD9D-D334C7FEFC1F}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {FD4BD8E8-6E3B-A815-CD9D-D334C7FEFC1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {FD4BD8E8-6E3B-A815-CD9D-D334C7FEFC1F}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {FD4BD8E8-6E3B-A815-CD9D-D334C7FEFC1F}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {FD4BD8E8-6E3B-A815-CD9D-D334C7FEFC1F}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.3.5f1 2 | m_StandardAssetsVersion: 0 3 | -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/UnityAdsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/UnityAdsSettings.asset -------------------------------------------------------------------------------- /Client/CoreClient/ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Client/CoreClient/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DotNetCore Tutorial for Unity3d for absolute noobs 2 | 3 | 4 | ## What is .NET Core 5 | - Cross Platform C# 6 | - Runs from a folder on OSX or Linux 7 | - Stripped down high performance 8 | - WebApi / MVC is an http framework built on Core 9 | 10 | ## What is this ? 11 | - A minimalistic HTTP server with... 12 | - SQL(Lite) Database using Entity Framework 13 | - High Score Api Controller 14 | - Chat Websocket service 15 | - Unity3d client 16 | 17 | ## Prerequisites 18 | - GET IT https://www.microsoft.com/net/core#windows 19 | - READ IT https://docs.asp.net/en/latest/tutorials/first-web-api.html 20 | 21 | ## Official Links 22 | - [Installation Guide](https://docs.efproject.net/en/latest/cli/dotnet.html#installation) 23 | - [Github repo for dotnetcore](https://dotnet.github.io/) 24 | - [SLACK SUPPORT !](http://tattoocoder.com/aspnet-slack-sign-up/) 25 | - [Entity Framework Wiki](https://github.com/aspnet/EntityFramework/wiki) 26 | 27 | ## Tools 28 | - [Chrome HTTP Client](www.getpostman.com) 29 | - [Chrome Websocket Client](https://github.com/hakobera/Simple-WebSocket-Client) 30 | - [Docker tutorial] (http://blog.alexellis.io/instant-dotnet-core-rc2-with-docker/) 31 | - [Digital Ocean Videos](https://www.youtube.com/watch?v=IpwHTs7QbQs) 32 | 33 | 34 | ## Good Samples 35 | - [MVC Music Store 'website'](https://docs.asp.net/en/latest/tutorials/first-mvc-app/index.html) 36 | 37 | ## Good to knows 38 | - [Routing Deep Dive](http://stephenwalther.com/archive/2015/02/07/asp-net-5-deep-dive-routing) 39 | - [Basic Websockets](https://medium.com/@turowicz/websockets-in-asp-net-5-6094319a15a2#.kejwy8ync) 40 | - [Async Locks](http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx) 41 | - [Custom View Locations](http://hossambarakat.net/2016/02/16/asp-net-core-mvc-feature-folders/) 42 | - [JWT Authentication](http://stackoverflow.com/questions/30546542/token-based-authentication-in-asp-net-5-vnext-refreshed/33217340#33217340) 43 | - [OAuth LinkedIn Example](https://auth0.com/blog/2016/06/13/authenticating-a-user-with-linkedin-in-aspnet-core/) 44 | - [ELMAH exception web viewer](http://dotnetthoughts.net/using-elmah-in-aspnet-core/) 45 | - [OData protocal (Lambda Queries !)](http://www.odata.org/) 46 | 47 | 48 | ## Facts 49 | - All apps in dotnetcore are glorified console apps. Program.cs is our entry point. 50 | - In Startup.cs we configure the MVC/WebApi part of the app. 51 | - Besides Startup and Program.cs code exists as /Infrastructure or /Modules 52 | - Infrastructure includes utilities and componenets 53 | - Modules includes domain services, controllers, and models 54 | - MVC has some magic that might be hard to grasp. 55 | - Routing is the convention to send HTTP requests to 'controllers' 56 | - View Location is the convention for finding html 'views' from controllers (for non API controller) 57 | - Entity framework defines a database using annotations 58 | - ModelState can validate a data object using annotations 59 | 60 | ## Entity Framework 61 | Entity framework is an Database Object Relationship Manager. Simply put, it is a strongly typed api for manipulating and persistent data. With EF you have a DataContext (the database object and unit of work). Inside the context you have DBSets, a collection type, one for each table in the database. DBSets are generic of you entity type. Entities define your table columns by way of properties and annotations. Everything in EF is code first, so, you write a C# file, close your eyes and you have a database. There are many other features such as navigational properties (table joins) and providers for other database types such as postgres. 62 | 63 | We will use something called Nuget to import dependencies. 64 | 65 | - Open PackageManagerConsole 66 | 67 | - Type This 68 | 69 | > Install-Package Microsoft.EntityFrameworkCore -Pre 70 | 71 | > Install-Package Microsoft.EntityFrameworkCore.Tools -Pre 72 | 73 | > Install-Package Microsoft.EntityFrameworkCore.Sqlite -Pre 74 | 75 | > *PROTIP* Update-Package -reinstall will re-reference all dlls if things break 76 | 77 | 78 | ### Define a database 79 | 80 | - Open ScoreModel.cs, this defines our single data table 81 | - Open ScoreContext.cs, this defines our database 82 | - Note that we ensure the database is create in Program.cs 83 | - Generally the database would exist outside in a shared domain and reference models from all domains. 84 | - The ScoreContext defines that it is using SQLite, this should really be handled by Startup 85 | 86 | ## Test it 87 | 88 | - On the project file, right click, options, set the default url to point to our ScoreController 89 | - I use POSTMON chrome extension, now make up some HTTP requests to the server 90 | - Server supports GET/ POST / DELETE verbs 91 | - GET http://{url}/api/Score 92 | - GET http://{url}/api/Score/{id} 93 | - POST http://{url}/api/Score/ (with Json Body 94 | - Delete http://{url}/api/Score/{id} 95 | 96 | ## Setup socket for real time chat 97 | 98 | - Get the Nuget package 99 | 100 | > Import-Package Microsoft.AspNetCore.WebSockets.Server -Pre 101 | 102 | - You will need to define a handler for websocket requests (ChatService.cs and ChatClient.cs). 103 | 104 | - You will also need to register this with the web app in Startup.cs 105 | 106 | - You can test it (Websocket extension above) by connectin to ws://{localhost:port} 107 | 108 | - The chat service is a simple broadcast relay 109 | 110 | 111 | ## Unity Example 112 | 113 | look at the code. Everything runs from Debug ContextMenu commands on the debug behaviour instance (on the main camera). Running the app is required for the chat demo due to main thread callback mechinism. 114 | -------------------------------------------------------------------------------- /Server/.vs/CoreWeb1/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVentimiglia/DotNetCoreUnity3d/fecc8f786f1fd829f207eedd5c1f123fdc8bb78d/Server/.vs/CoreWeb1/v14/.suo -------------------------------------------------------------------------------- /Server/.vs/config/applicationhost.config: -------------------------------------------------------------------------------- 1 |  2 | 20 | 21 | 48 | 49 | 50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | 59 | 60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | 78 |
79 |
80 | 81 |
82 |
83 |
84 |
85 |
86 |
87 | 88 |
89 |
90 |
91 |
92 |
93 | 94 |
95 |
96 |
97 | 98 |
99 |
100 | 101 |
102 |
103 | 104 |
105 |
106 |
107 | 108 | 109 |
110 |
111 |
112 |
113 |
114 |
115 | 116 |
117 |
118 |
119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | -------------------------------------------------------------------------------- /Server/.vs/restore.dg: -------------------------------------------------------------------------------- 1 | #:F:\Drive\Samples\Core\CoreWeb1\Server\src\CoreWeb1\CoreWeb1.xproj 2 | -------------------------------------------------------------------------------- /Server/CoreWeb1.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B53DEADB-04A1-4E3D-9753-9C13976FD389}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FAC61673-4F69-4591-B1B9-149B6D642373}" 9 | ProjectSection(SolutionItems) = preProject 10 | global.json = global.json 11 | EndProjectSection 12 | EndProject 13 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CoreWeb1", "src\CoreWeb1\CoreWeb1.xproj", "{D4107CCC-C118-4939-8139-79B6BF717C1A}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {D4107CCC-C118-4939-8139-79B6BF717C1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {D4107CCC-C118-4939-8139-79B6BF717C1A}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {D4107CCC-C118-4939-8139-79B6BF717C1A}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 24 | {D4107CCC-C118-4939-8139-79B6BF717C1A}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {D4107CCC-C118-4939-8139-79B6BF717C1A}.Release|Any CPU.Build.0 = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | GlobalSection(NestedProjects) = preSolution 31 | {D4107CCC-C118-4939-8139-79B6BF717C1A} = {B53DEADB-04A1-4E3D-9753-9C13976FD389} 32 | EndGlobalSection 33 | EndGlobal 34 | -------------------------------------------------------------------------------- /Server/global.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": [ "src", "test" ], 3 | "sdk": { 4 | "version": "1.0.0-preview2-003121" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Controllers/ChatService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.WebSockets; 3 | using System.Threading.Tasks; 4 | using CoreWeb1.Data; 5 | using Microsoft.AspNetCore.Http; 6 | 7 | namespace CoreWeb1.Controllers 8 | { 9 | public class ChatService 10 | { 11 | static List _connections = new List(); 12 | static object _lock = new object(); 13 | 14 | 15 | private readonly RequestDelegate next; 16 | 17 | public ChatService(RequestDelegate next) 18 | { 19 | this.next = next; 20 | } 21 | 22 | public async Task Invoke(HttpContext http) 23 | { 24 | // is this http request a WS request ? 25 | if (http.WebSockets.IsWebSocketRequest) 26 | { 27 | //Accept handshake 28 | var webSocket = await http.WebSockets.AcceptWebSocketAsync(); 29 | 30 | // sanity for failed handshake 31 | if (webSocket != null && webSocket.State == WebSocketState.Open) 32 | { 33 | //make a new client reference 34 | var client = new ChatClient(webSocket, bytes => 35 | { 36 | //receive handler 37 | //here we just broadcast the new message to everyone 38 | lock (_lock) 39 | { 40 | _connections.ForEach(o => o.Send(bytes)); 41 | } 42 | }); 43 | 44 | //add it to mgmt 45 | lock (_lock) 46 | { 47 | _connections.Add(client); 48 | } 49 | 50 | //while open 'Update' (read the incoming socket stream) 51 | await client.UpdateAsync(); 52 | 53 | //note, this returns only when the stream is closed 54 | 55 | //dispose, remove, close 56 | client.Dispose(); 57 | lock (_lock) 58 | { 59 | _connections.Remove(client); 60 | } 61 | } 62 | } 63 | else 64 | { 65 | // Nothing to do here, pass downstream. 66 | await next(http); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | // For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 4 | 5 | namespace CoreWeb1.Controllers 6 | { 7 | [Route("/Home/")] 8 | public class HomeController : Controller 9 | { 10 | // GET: // 11 | public IActionResult Index() 12 | { 13 | return View(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Controllers/ScoreController.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using CoreWeb1.Data; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace CoreWeb1.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | public class ScoreController : Controller 11 | { 12 | //Ref to our DB proxy 13 | protected ScoreContext Context = new ScoreContext(); 14 | protected override void Dispose(bool disposing) 15 | { 16 | base.Dispose(disposing); 17 | Context.Dispose(); 18 | 19 | } 20 | 21 | // GET api/Score 22 | [HttpGet] 23 | public async Task Get() 24 | { 25 | // PROTIP : filter these results using http paramaters or something like ODATA 26 | // ODATA exposes full lambda searches to the client 27 | 28 | return new ScoreModelContainer 29 | { 30 | Scores = await Queryable.OrderByDescending(Context.Scores, o => o.Points).ToArrayAsync() 31 | }; 32 | } 33 | 34 | // GET api/Score/5 35 | [HttpGet("{id}")] 36 | public Task Get(string id) 37 | { 38 | return Context.Scores.FirstOrDefaultAsync(o => o.UserName == id); 39 | } 40 | 41 | // POST api/Score 42 | [HttpPost] 43 | public async Task Post([FromBody]ScoreModel model) 44 | { 45 | //Sanity 46 | if (!ModelState.IsValid) 47 | { 48 | return BadRequest("Bad Username or something"); 49 | } 50 | 51 | //Check for new or update 52 | var old = await Context.Scores.FirstOrDefaultAsync(o => o.UserName == model.UserName); 53 | 54 | if (old == null) 55 | { 56 | //New 57 | Context.Scores.Add(model); 58 | await Context.SaveChangesAsync(); 59 | 60 | return Ok(model); 61 | } 62 | else 63 | { 64 | //UPDATE 65 | old.Points = model.Points; 66 | await Context.SaveChangesAsync(); 67 | return Ok(model); 68 | } 69 | } 70 | 71 | // DELETE api/Score/5 72 | [HttpDelete("{id}")] 73 | public async Task Delete(string id) 74 | { 75 | //Check for new or update 76 | var old = await Context.Scores.FirstOrDefaultAsync(o => o.UserName == id); 77 | if (old != null) 78 | { 79 | Context.Scores.Remove(old); 80 | await Context.SaveChangesAsync(); 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Controllers/ScoreController.cs.old: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | namespace CoreWeb1.Modules.Score 9 | { 10 | [Route("api/[controller]")] 11 | public class ScoreController : Controller 12 | { 13 | //Ref to our DB proxy 14 | protected ScoreContext Context = new ScoreContext(); 15 | protected override void Dispose(bool disposing) 16 | { 17 | base.Dispose(disposing); 18 | Context.Dispose(); 19 | } 20 | 21 | // GET api/Score 22 | [HttpGet] 23 | public IEnumerable Get() 24 | { 25 | // PROTIP : filter these results using http paramaters or something like ODATA 26 | // ODATA exposes full lambda searches to the client 27 | return Context.Scores.OrderByDescending(o => o.Points); 28 | } 29 | 30 | // GET api/Score/5 31 | [HttpGet("{id}")] 32 | public Task Get(string id) 33 | { 34 | return Context.Scores.FirstOrDefaultAsync(o => o.UserName == id); 35 | } 36 | 37 | // POST api/Score 38 | [HttpPost] 39 | public async Task Post([FromBody]ScoreModel model) 40 | { 41 | //Sanity 42 | if (!ModelState.IsValid) 43 | { 44 | return BadRequest("Bad Username or something"); 45 | } 46 | 47 | //Check for new or update 48 | var old = await Context.Scores.FirstOrDefaultAsync(o => o.UserName == model.UserName); 49 | 50 | if (old == null) 51 | { 52 | //New 53 | Context.Scores.Add(model); 54 | await Context.SaveChangesAsync(); 55 | 56 | return Ok(model); 57 | } 58 | else 59 | { 60 | //UPDATE 61 | old.Points = model.Points; 62 | await Context.SaveChangesAsync(); 63 | return Ok(model); 64 | } 65 | } 66 | 67 | // DELETE api/Score/5 68 | [HttpDelete("{id}")] 69 | public async Task Delete(string id) 70 | { 71 | //Check for new or update 72 | var old = await Context.Scores.FirstOrDefaultAsync(o => o.UserName == id); 73 | if (old != null) 74 | { 75 | Context.Scores.Remove(old); 76 | await Context.SaveChangesAsync(); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/CoreWeb1.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | d4107ccc-c118-4939-8139-79b6bf717c1a 10 | CoreWeb1 11 | .\obj 12 | .\bin\ 13 | v4.5.2 14 | 15 | 16 | 2.0 17 | 0.21 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/CoreWeb1.xproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | IIS Express 5 | 6 | 7 | IIS Express 8 | ProjectDebugger 9 | 10 | 11 | Docker 12 | ProjectDebugger 13 | 14 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Data/ChatClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.WebSockets; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using CoreWeb1.Infrastructure.AsyncLock; 6 | 7 | namespace CoreWeb1.Data 8 | { 9 | ///Minmalistic Websocket instance handler 10 | public class ChatClient : IDisposable 11 | { 12 | 13 | ///Is Valid for sending / receiving 14 | public bool IsOpen 15 | { 16 | get { return socket != null && !error && socket.State == WebSocketState.Open; } 17 | } 18 | 19 | WebSocket socket; 20 | byte[] buffer = new byte[1024]; 21 | AsyncLock _lock = new AsyncLock(); 22 | Action onMessage; 23 | private bool error = false; 24 | 25 | ///Create a new client reference 26 | public ChatClient(WebSocket socket, Action onMessage) 27 | { 28 | this.socket = socket; 29 | this.onMessage = onMessage; 30 | } 31 | 32 | public void Dispose() 33 | { 34 | //race dispose pattern 35 | var mSock = socket; 36 | socket = null; 37 | if (mSock != null) 38 | mSock.Dispose(); 39 | } 40 | 41 | ///Processes the websocket, returns on socket failure 42 | public async Task UpdateAsync() 43 | { 44 | WebSocketReceiveResult received = await socket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); 45 | 46 | while (received.MessageType != WebSocketMessageType.Close && !error) 47 | { 48 | if (received.MessageType == WebSocketMessageType.Text) 49 | { 50 | onMessage(buffer); 51 | } 52 | 53 | received = await socket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); 54 | } 55 | } 56 | 57 | ///relays a text message to the client instance 58 | public async void Send(byte[] message) 59 | { 60 | try 61 | { 62 | if (socket == null || socket.State != WebSocketState.Open) 63 | return; 64 | 65 | //utilize the bytes 66 | var payload = new ArraySegment(message, 0, message.Length); 67 | 68 | //can only send one at a time 69 | using (var releaser = await _lock.LockAsync()) 70 | { 71 | await socket.SendAsync(payload, WebSocketMessageType.Text, true, CancellationToken.None); 72 | } 73 | 74 | } 75 | catch (Exception ex) 76 | { 77 | // Will happen on client disconnect since we dont have a HB to auto cleanup 78 | Console.Write(ex.Message); 79 | error = true; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Data/ScoreContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace CoreWeb1.Data 4 | { 5 | /// 6 | /// Defines our database. 7 | /// 8 | public class ScoreContext : DbContext 9 | { 10 | /// 11 | /// Defines a single table of scores 12 | /// 13 | public DbSet Scores { get; set; } 14 | 15 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 16 | { 17 | // TODO move to startup 18 | optionsBuilder.UseSqlite("Filename=./score.db"); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Data/ScoreModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace CoreWeb1.Data 4 | { 5 | /// 6 | /// This entity is persistent via the ScoreContext 7 | /// 8 | public class ScoreModel 9 | { 10 | //Key defines our primary lookup id 11 | 12 | /// 13 | /// UNIQUE Name, using an ID is a better practice 14 | /// 15 | [Key] 16 | public string UserName { get; set; } 17 | 18 | /// 19 | /// Uses score 20 | /// 21 | public int Points { get; set; } 22 | } 23 | 24 | /// 25 | /// Client side data model. 26 | /// This can be shared...... 27 | /// 28 | /// 29 | /// Because Unity json serializer does not know how to deserialize arrays. 30 | /// 31 | public class ScoreModelContainer 32 | { 33 | public ScoreModel[] Scores { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Dockerfile: -------------------------------------------------------------------------------- 1 | #dotnet build 2 | #dotnet publish 3 | #cd bin/Debug/netcoreapp1.0/publish 4 | #docker build -t nventi/coreweb:latest 5 | #docker run -d -p 5000:5000 nventi/coreweb:latest 6 | #docker ps 7 | 8 | FROM microsoft/dotnet:latest 9 | 10 | # Set the Working Directory 11 | WORKDIR /app 12 | 13 | # Configure the listening port 14 | ENV ASPNETCORE_URLS http://*:80 15 | EXPOSE 80 16 | 17 | # Copy the app 18 | COPY . /app 19 | 20 | # Start the app 21 | ENTRYPOINT dotnet CoreWeb1.dll 22 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Infrastructure/AsyncLock/AsyncLock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace CoreWeb1.Infrastructure.AsyncLock 6 | { 7 | public class AsyncLock 8 | { 9 | private readonly AsyncSemaphore m_semaphore; 10 | private readonly Task m_releaser; 11 | 12 | public AsyncLock() 13 | { 14 | m_semaphore = new AsyncSemaphore(1); 15 | m_releaser = Task.FromResult(new Releaser(this)); 16 | } 17 | 18 | public Task LockAsync() 19 | { 20 | var wait = m_semaphore.WaitAsync(); 21 | return wait.IsCompleted ? 22 | m_releaser : 23 | wait.ContinueWith((_, state) => new Releaser((AsyncLock)state), 24 | this, CancellationToken.None, 25 | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); 26 | } 27 | 28 | public struct Releaser : IDisposable 29 | { 30 | private readonly AsyncLock m_toRelease; 31 | 32 | internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; } 33 | 34 | public void Dispose() 35 | { 36 | if (m_toRelease != null) 37 | m_toRelease.m_semaphore.Release(); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Infrastructure/AsyncLock/AsyncSemaphore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace CoreWeb1.Infrastructure.AsyncLock 6 | { 7 | // http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx 8 | public class AsyncSemaphore 9 | { 10 | private readonly static Task s_completed = Task.FromResult(true); 11 | private readonly Queue> m_waiters = new Queue>(); 12 | private int m_currentCount; 13 | 14 | public AsyncSemaphore(int initialCount) 15 | { 16 | if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount"); 17 | m_currentCount = initialCount; 18 | } 19 | 20 | public Task WaitAsync() 21 | { 22 | lock (m_waiters) 23 | { 24 | if (m_currentCount > 0) 25 | { 26 | --m_currentCount; 27 | return s_completed; 28 | } 29 | else 30 | { 31 | var waiter = new TaskCompletionSource(); 32 | m_waiters.Enqueue(waiter); 33 | return waiter.Task; 34 | } 35 | } 36 | } 37 | 38 | public void Release() 39 | { 40 | TaskCompletionSource toRelease = null; 41 | lock (m_waiters) 42 | { 43 | if (m_waiters.Count > 0) 44 | toRelease = m_waiters.Dequeue(); 45 | else 46 | ++m_currentCount; 47 | } 48 | if (toRelease != null) 49 | toRelease.SetResult(true); 50 | } 51 | } 52 | 53 | // http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx 54 | } 55 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Infrastructure/ModuleViewLocator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.AspNetCore.Mvc.Razor; 3 | 4 | namespace CoreWeb1.Infrastructure 5 | { 6 | /// 7 | /// Support for the Modules/Domain/Views 8 | /// http://hossambarakat.net/2016/02/16/asp-net-core-mvc-feature-folders/ 9 | /// Not being used as this app is small. would use in a production app. 10 | /// 11 | public class ModuleViewLocator : IViewLocationExpander 12 | { 13 | public void PopulateValues(ViewLocationExpanderContext context) 14 | { 15 | context.Values["customviewlocation"] = nameof(ModuleViewLocator); 16 | } 17 | 18 | public IEnumerable ExpandViewLocations( 19 | ViewLocationExpanderContext context, 20 | IEnumerable viewLocations) 21 | { 22 | var viewLocationFormats = new[] 23 | { 24 | "~/Modules/{1}/Views/{0}.cshtml", 25 | "~/Modules/Shared/Views/{0}.cshtml", 26 | }; 27 | return viewLocationFormats; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Microsoft.AspNetCore.Hosting; 4 | 5 | namespace CoreWeb1 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | var host = new WebHostBuilder() 12 | // Required for docker support 13 | .UseUrls(Environment.GetEnvironmentVariable("ASPNETCORE_SERVER.URLS")) 14 | // Kestrel is the web server 15 | .UseKestrel() 16 | // cus windows ? 17 | .UseIISIntegration() 18 | // root for our content (resources such as CSS stlyes, donts, images and Yavascript) 19 | .UseContentRoot(Directory.GetCurrentDirectory()) 20 | // more customized and app specific configuration 21 | .UseStartup() 22 | // end of configuration 23 | .Build(); 24 | 25 | //Run the web server 26 | host.Run(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Properties/Docker.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 6 | 7 | 8 | 10 | default 11 | 12 | 13 | dotnet 14 | /app/CoreWeb1.dll 15 | /app/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Properties/Docker.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | False 5 | 6 | 7 | 8 | 9 | 10 | SetDockerProps; 11 | CoreDockerBuild; 12 | 13 | 14 | SetDockerProps; 15 | CoreDockerClean; 16 | 17 | 18 | SetDockerProps; 19 | CoreDockerBeforeRebuild; 20 | 21 | 22 | 23 | 24 | 25 | 26 | True 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | powershell -ExecutionPolicy RemoteSigned .\DockerTask.ps1 -Build -Environment $(Configuration) -Machine '$(DockerMachineName)' -ClrDebugVersion VS2015U2 35 | $(DockerBuildCommand) -NoCache 36 | 37 | 38 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | powershell -ExecutionPolicy RemoteSigned .\DockerTask.ps1 -Clean -Environment $(Configuration) -Machine '$(DockerMachineName)' 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | True 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:58459/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "Home", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "CoreWeb1": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "launchUrl": "http://localhost:5000/api/values", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | }, 27 | "Docker": {} 28 | } 29 | } -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Startup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using CoreWeb1.Controllers; 3 | using CoreWeb1.Data; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace CoreWeb1 11 | { 12 | public class Startup 13 | { 14 | public Startup(IHostingEnvironment env) 15 | { 16 | // Things such as.. 17 | // Debug level 18 | // database connection strings 19 | // admin email address 20 | // and other quasi dynamic configuration data 21 | var builder = new ConfigurationBuilder() 22 | .SetBasePath(env.ContentRootPath) 23 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 24 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); 25 | 26 | builder.AddEnvironmentVariables(); 27 | Configuration = builder.Build(); 28 | } 29 | 30 | public IConfigurationRoot Configuration { get; } 31 | 32 | // This method gets called by the runtime. Use this method to add services to the container 33 | public void ConfigureServices(IServiceCollection services) 34 | { 35 | //our routing framework 36 | services.AddMvc().AddJsonOptions(options => 37 | { 38 | // PascaleCaseJson 39 | options.SerializerSettings.ContractResolver = new DefaultContractResolver(); 40 | }); 41 | } 42 | 43 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline 44 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 45 | { 46 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 47 | loggerFactory.AddDebug(); 48 | 49 | //enable web sockets 50 | app.UseWebSockets(); 51 | 52 | //wire our chat service 53 | app.UseMiddleware(); 54 | 55 | // this enables routing / controller framework 56 | app.UseMvc(); 57 | 58 | //ensure DB is configured 59 | using (var context = new ScoreContext()) 60 | { 61 | context.Database.EnsureCreated(); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Welcome

4 |
5 |

Your server is up and running. The time is @System.DateTime.UtcNow.TimeOfDay.ToString() UTC.

6 |
7 | Nicholas Ventimiglia 8 | Project Github 9 |
10 |
11 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "Microsoft.NETCore.App": { 4 | "version": "1.0.0", 5 | "type": "platform" 6 | }, 7 | "Microsoft.AspNetCore.Mvc": "1.0.0", 8 | "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", 9 | "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", 10 | "Microsoft.AspNetCore.StaticFiles": "1.0.0", 11 | "Microsoft.AspNetCore.WebSockets.Server": "0.1.0", 12 | "Microsoft.EntityFrameworkCore.Sqlite": "1.0.0", 13 | "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", 14 | "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", 15 | "Microsoft.Extensions.Configuration.Json": "1.0.0", 16 | "Microsoft.Extensions.Logging": "1.0.0", 17 | "Microsoft.Extensions.Logging.Console": "1.0.0", 18 | "Microsoft.Extensions.Logging.Debug": "1.0.0" 19 | }, 20 | "tools": { 21 | "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", 22 | "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final" 23 | }, 24 | "frameworks": { 25 | "netcoreapp1.0": { 26 | "imports": [ 27 | "dotnet5.6", 28 | "dnxcore50", 29 | "portable-net45+win8" 30 | ] 31 | } 32 | }, 33 | "buildOptions": { 34 | "emitEntryPoint": true, 35 | "preserveCompilationContext": true, 36 | "debugType": "portable" 37 | }, 38 | "runtimeOptions": { 39 | "configProperties": { 40 | "System.GC.Server": true 41 | } 42 | }, 43 | "publishOptions": { 44 | "include": [ 45 | "wwwroot", 46 | "Views", 47 | "appsettings.json", 48 | "web.config", 49 | "Dockerfile", 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Server/src/CoreWeb1/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | --------------------------------------------------------------------------------