Added a socket client
This commit is contained in:
31
Server Dashboard Socket/Channel/ClientChannel.cs
Normal file
31
Server Dashboard Socket/Channel/ClientChannel.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server_Dashboard_Socket {
|
||||
/// <summary>
|
||||
/// Client Socket
|
||||
/// </summary>
|
||||
/// <typeparam name="TProtocol">The Protocol type, either JsonMessageProtocol or XmlMessageProtocol</typeparam>
|
||||
/// <typeparam name="TMessageType">The message type, either JObject or XDocument</typeparam>
|
||||
public class ClientChannel<TProtocol, TMessageType> : SocketChannel<TProtocol, TMessageType>
|
||||
where TProtocol : Protocol<TMessageType>, new(){
|
||||
|
||||
/// <summary>
|
||||
/// Connect to the socket async
|
||||
/// </summary>
|
||||
/// <param name="endpoint">An endpoint with an IP address and port</param>
|
||||
/// <returns></returns>
|
||||
public async Task ConnectAsync(IPEndPoint endpoint) {
|
||||
//Creates a new Socket
|
||||
var socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
//Connects to the socket
|
||||
await socket.ConnectAsync(endpoint).ConfigureAwait(false);
|
||||
//Attach the socket to a network stream
|
||||
Attach(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
95
Server Dashboard Socket/Channel/SocketChannel.cs
Normal file
95
Server Dashboard Socket/Channel/SocketChannel.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server_Dashboard_Socket {
|
||||
/// <summary>
|
||||
/// Generic Channel class that handles the connection and message sending / receiving
|
||||
/// Inherits IDisposable to correctly cut the connection to the server
|
||||
/// </summary>
|
||||
/// <typeparam name="TProtocol">The Protocol type, either JsonMessageProtocol or XmlMessageProtocol</typeparam>
|
||||
/// <typeparam name="TMessageType">The message type, either JObject or XDocument</typeparam>
|
||||
public abstract class SocketChannel<TProtocol, TMessageType> : IDisposable
|
||||
where TProtocol : Protocol<TMessageType>, new() {
|
||||
|
||||
protected bool isDisposable = false;
|
||||
NetworkStream networkStream;
|
||||
readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
|
||||
readonly TProtocol protocol = new TProtocol();
|
||||
|
||||
Func<TMessageType, Task> messageCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Attaches the socket to a network stream that owns the socket
|
||||
/// if the network stream goes down it takes the socket with it!
|
||||
/// </summary>
|
||||
/// <param name="socket">A Socket</param>
|
||||
public void Attach(Socket socket) {
|
||||
networkStream = new NetworkStream(socket, true);
|
||||
_ = Task.Run(ReceiveLoop, cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a function with a message and sets the private member to the functions value
|
||||
/// </summary>
|
||||
/// <param name="callbackHandler"></param>
|
||||
public void OnMessage(Func<TMessageType, Task> callbackHandler) => messageCallback = callbackHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Makes sure to close the socket
|
||||
/// </summary>
|
||||
public void Close() {
|
||||
cancellationTokenSource.Cancel();
|
||||
networkStream?.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the message async
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Anything as message, e.g. object or string</typeparam>
|
||||
/// <param name="message">The message</param>
|
||||
/// <returns></returns>
|
||||
public async Task SendAsync<T>(T message) => await protocol.SendAsync(networkStream, message).ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Checks for received messages
|
||||
/// </summary>
|
||||
/// <returns>received message</returns>
|
||||
protected virtual async Task ReceiveLoop() {
|
||||
while (!cancellationTokenSource.Token.IsCancellationRequested) {
|
||||
var msg = await protocol.ReceiveAsync(networkStream).ConfigureAwait(false);
|
||||
await messageCallback(msg).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deconstructor sets Dispose to false
|
||||
/// </summary>
|
||||
~SocketChannel() => Dispose(false);
|
||||
/// <summary>
|
||||
/// Sets dispose to true
|
||||
/// </summary>
|
||||
public void Dispose() => Dispose(true);
|
||||
/// <summary>
|
||||
/// Disposes open sockets
|
||||
/// </summary>
|
||||
/// <param name="isDisposing">Is it currently disposing stuff?</param>
|
||||
protected void Dispose(bool isDisposing) {
|
||||
//If its not disposable
|
||||
if (!isDisposable) {
|
||||
//Set disposable to true
|
||||
isDisposable = true;
|
||||
//Close the socket
|
||||
Close();
|
||||
//If its closed, dispose it
|
||||
networkStream?.Dispose();
|
||||
//Wait with the garbage collection untill the disposing is done
|
||||
if (isDisposing)
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Server Dashboard Socket/Client/SocketClient.cs
Normal file
90
Server Dashboard Socket/Client/SocketClient.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
using Server_Dashboard_Socket.Protocol;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Server_Dashboard_Socket {
|
||||
public class SocketClient {
|
||||
|
||||
public SocketClient() {
|
||||
//Starts the echo server for testing purposes
|
||||
EchoServer echoServer = new EchoServer();
|
||||
echoServer.Start();
|
||||
//Start the Socket test
|
||||
Start();
|
||||
}
|
||||
|
||||
private async void Start() {
|
||||
//Creates a new endpoint with the IP adress and port
|
||||
var endpoint = new IPEndPoint(IPAddress.Loopback, 9000);
|
||||
|
||||
//Creates a new Channel for the Json protocol
|
||||
var channel = new ClientChannel<JsonMessageProtocol, JObject>();
|
||||
//Creates a new Channel for the XDocument protocol
|
||||
//var channel = new ClientChannel<XmlMessageProtocol, XDocument>();
|
||||
|
||||
//Callback for the message
|
||||
channel.OnMessage(OnMessage);
|
||||
|
||||
//Connect to the Socket
|
||||
await channel.ConnectAsync(endpoint).ConfigureAwait(false);
|
||||
|
||||
//Test message
|
||||
var myMessage = new MyMessage {
|
||||
IntProperty = 404,
|
||||
StringProperty = "Hello World!"
|
||||
};
|
||||
//Send the test message
|
||||
await channel.SendAsync(myMessage).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When it receives a message it gets converted from Json back to MyMessage
|
||||
/// </summary>
|
||||
/// <param name="jobject">The json to be converted back</param>
|
||||
/// <returns>Task completed</returns>
|
||||
static Task OnMessage(JObject jobject) {
|
||||
Console.WriteLine(Convert(jobject));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
/// <summary>
|
||||
/// When it receives a message it gets converted from XDocument back to MyMessage
|
||||
/// </summary>
|
||||
/// <param name="xDocument">The xml to be converted back</param>
|
||||
/// <returns>Task completed</returns>
|
||||
static Task OnMessage(XDocument xDocument) {
|
||||
Console.WriteLine(Convert(xDocument));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts json to MyMessage
|
||||
/// </summary>
|
||||
/// <param name="jObject">The json to be converted</param>
|
||||
/// <returns>MyMessage object</returns>
|
||||
static MyMessage Convert(JObject jObject) => jObject.ToObject(typeof(MyMessage)) as MyMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Converts XDocument to MyMessage
|
||||
/// </summary>
|
||||
/// <param name="xmlDocument">The xml to be converted</param>
|
||||
/// <returns>MyMessage object</returns>
|
||||
static MyMessage Convert(XDocument xmlDocument) => new XmlSerializer(typeof(MyMessage)).Deserialize(new StringReader(xmlDocument.ToString())) as MyMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MyMessage test class
|
||||
/// Delete later when Sockets are finished
|
||||
/// </summary>
|
||||
public class MyMessage {
|
||||
public int IntProperty { get; set; }
|
||||
public string StringProperty { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,26 +8,47 @@ namespace Server_Dashboard_Socket {
|
||||
/// Basic echo server to test the socket connection
|
||||
/// </summary>
|
||||
public class EchoServer {
|
||||
public void Start(int port = 9565) {
|
||||
/// <summary>
|
||||
/// Start the socket on 127.0.0.1:9000
|
||||
/// </summary>
|
||||
/// <param name="port">A port that is not already in use</param>
|
||||
public void Start(int port = 9000) {
|
||||
//Creates a new endpoint on 127.0.0.1 and the port 9000
|
||||
IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, port);
|
||||
//Creates a new Socket on the given endpoint
|
||||
Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
//Bind the endpoint to the socket
|
||||
socket.Bind(endPoint);
|
||||
//Define how many Clients you want to have connected max
|
||||
socket.Listen(128);
|
||||
//Just run the Task forever
|
||||
_ = Task.Run(() => DoEcho(socket));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Listens for messages and sends them back asap
|
||||
/// </summary>
|
||||
/// <param name="socket">The socket to work with</param>
|
||||
/// <returns>poop</returns>
|
||||
private async Task DoEcho(Socket socket) {
|
||||
while (true) {
|
||||
//Listen for incomming connection requests and accept them
|
||||
Socket clientSocket = await Task.Factory.FromAsync(
|
||||
new Func<AsyncCallback, object, IAsyncResult>(socket.BeginAccept),
|
||||
new Func<IAsyncResult, Socket>(socket.EndAccept),
|
||||
null).ConfigureAwait(false);
|
||||
//Create a network stream and make it the owner of the socket
|
||||
//This will close the socket if the stream is closed and vice verca
|
||||
using(NetworkStream stream = new NetworkStream(clientSocket, true)) {
|
||||
//New buffer for the message in bytes
|
||||
byte[] buffer = new byte[1024];
|
||||
while (true) {
|
||||
//Read everything that somes in
|
||||
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
//If its 0 just leave since its a obscolete connection
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
//Send it back to the sender
|
||||
await stream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
53
Server Dashboard Socket/Protocol/JsonMessageProtocol.cs
Normal file
53
Server Dashboard Socket/Protocol/JsonMessageProtocol.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Server_Dashboard_Socket.Protocol {
|
||||
/// <summary>
|
||||
/// Json serializer class
|
||||
/// </summary>
|
||||
public class JsonMessageProtocol : Protocol<JObject> {
|
||||
|
||||
//The Json serializer and the settings
|
||||
static readonly JsonSerializer serializer;
|
||||
static readonly JsonSerializerSettings settings;
|
||||
|
||||
/// <summary>
|
||||
/// Settings for the Json Serializer
|
||||
/// </summary>
|
||||
static JsonMessageProtocol() {
|
||||
//Set the settings
|
||||
settings = new JsonSerializerSettings {
|
||||
Formatting = Formatting.Indented,
|
||||
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
|
||||
ContractResolver = new DefaultContractResolver {
|
||||
NamingStrategy = new CamelCaseNamingStrategy {
|
||||
ProcessDictionaryKeys = false
|
||||
}
|
||||
}
|
||||
};
|
||||
settings.PreserveReferencesHandling = PreserveReferencesHandling.None;
|
||||
//Creates the serializer with the settings
|
||||
serializer = JsonSerializer.Create(settings);
|
||||
}
|
||||
//Decode the message, to Json
|
||||
protected override JObject Decode(byte[] message) => JObject.Parse(Encoding.UTF8.GetString(message));
|
||||
|
||||
/// <summary>
|
||||
/// Encode the body from Json to bytes
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The message type e.g. object or string</typeparam>
|
||||
/// <param name="message">The message to send</param>
|
||||
/// <returns>message as byte[]</returns>
|
||||
protected override byte[] EncodeBody<T>(T message) {
|
||||
var sb = new StringBuilder();
|
||||
var sw = new StringWriter(sb);
|
||||
serializer.Serialize(sw, message);
|
||||
return Encoding.UTF8.GetBytes(sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
132
Server Dashboard Socket/Protocol/Protocol.cs
Normal file
132
Server Dashboard Socket/Protocol/Protocol.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server_Dashboard_Socket {
|
||||
/// <summary>
|
||||
/// Generic Protocol class for Json and Xml serialization
|
||||
/// </summary>
|
||||
/// <typeparam name="TMessageType">JsonMessageProtocol or XmlMessageProtocol</typeparam>
|
||||
public abstract class Protocol<TMessageType> {
|
||||
//Header size is always 4
|
||||
const int HEADER_SIZE = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message and checks with the header if the message is valid or not
|
||||
/// important to defend against attacks with infinite long messages
|
||||
/// </summary>
|
||||
/// <param name="networkStream">A network stream</param>
|
||||
/// <returns>MessageType e.g. Json or Xml</returns>
|
||||
public async Task<TMessageType> ReceiveAsync(NetworkStream networkStream) {
|
||||
//Gets the body length
|
||||
int bodyLength = await ReadHeader(networkStream).ConfigureAwait(false);
|
||||
//Validates the length
|
||||
AssertValidMessageLength(bodyLength);
|
||||
//Returns the body message type
|
||||
return await Readbody(networkStream, bodyLength).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends data Async
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Message type e.g. object or string</typeparam>
|
||||
/// <param name="networkStream">Network stream</param>
|
||||
/// <param name="message">The message</param>
|
||||
/// <returns></returns>
|
||||
public async Task SendAsync<T>(NetworkStream networkStream, T message) {
|
||||
//encodes the message to a header and body
|
||||
var (header, body) = Encode(message);
|
||||
//Sends the header
|
||||
await networkStream.WriteAsync(header, 0, header.Length).ConfigureAwait(false);
|
||||
//Sends the body
|
||||
await networkStream.WriteAsync(body, 0, body.Length).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the header and converts it to an integer
|
||||
/// </summary>
|
||||
/// <param name="networkStream">A network stream</param>
|
||||
/// <returns>Header as Integer</returns>
|
||||
async Task<int> ReadHeader(NetworkStream networkStream) {
|
||||
byte[] headerBytes = await ReadAsync(networkStream, HEADER_SIZE).ConfigureAwait(false);
|
||||
return IPAddress.HostToNetworkOrder(BitConverter.ToInt32(headerBytes));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the body and decodes it to a human readable string
|
||||
/// </summary>
|
||||
/// <param name="networkStream">A network stream</param>
|
||||
/// <param name="bodyLength">Length of the body</param>
|
||||
/// <returns>Decoded body</returns>
|
||||
async Task<TMessageType> Readbody(NetworkStream networkStream, int bodyLength) {
|
||||
//Reads the bytes from the stream into an array
|
||||
byte[] bodyBytes = await ReadAsync(networkStream, bodyLength).ConfigureAwait(false);
|
||||
//Decodes it and returns the string
|
||||
return Decode(bodyBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the network stream as long as something is readable
|
||||
/// </summary>
|
||||
/// <param name="networkStream">A network stream</param>
|
||||
/// <param name="bytesToRead">how many bytes there are to read</param>
|
||||
/// <returns>Every byte from the Stream</returns>
|
||||
async Task<byte[]> ReadAsync(NetworkStream networkStream, int bytesToRead) {
|
||||
//new buffer that is as big as the content(watch out for buffer overflows)
|
||||
byte[] buffer = new byte[bytesToRead];
|
||||
//keep acount of the bytes that are already read
|
||||
int bytesRead = 0;
|
||||
//White we still have something to read
|
||||
while(bytesRead < bytesToRead){
|
||||
//Read it from the stream
|
||||
var bytesReceived = await networkStream.ReadAsync(buffer, bytesRead, (bytesToRead - bytesRead)).ConfigureAwait(false);
|
||||
//If it happens to be 0 close the socket
|
||||
if (bytesReceived == 0)
|
||||
throw new Exception("Socket Closed");
|
||||
bytesRead += bytesReceived;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode the message from human readable to bytes for the stream
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The message as anything e.g. object or strng</typeparam>
|
||||
/// <param name="message">The message to be send</param>
|
||||
/// <returns>The Header and Body as bytes[]</returns>
|
||||
protected (byte[] header, byte[] body) Encode<T>(T message) {
|
||||
//Creates the body bytes
|
||||
var bodyBytes = EncodeBody(message);
|
||||
//Creates the header bytes
|
||||
var headerBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(bodyBytes.Length));
|
||||
return (headerBytes, bodyBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode the message with the given type, json or xml
|
||||
/// </summary>
|
||||
/// <param name="message">The message to decode</param>
|
||||
/// <returns>Decoded message</returns>
|
||||
protected abstract TMessageType Decode(byte[] message);
|
||||
|
||||
/// <summary>
|
||||
/// Validate the message length to combat attacks
|
||||
/// </summary>
|
||||
/// <param name="messageLength">The message length</param>
|
||||
protected virtual void AssertValidMessageLength(int messageLength) {
|
||||
//If its not 0 throw an exception
|
||||
if (messageLength < 1)
|
||||
throw new ArgumentOutOfRangeException("Invalid message length");
|
||||
}
|
||||
/// <summary>
|
||||
/// Encode the message so it can be send via the network stream
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Message type e.g. object or string</typeparam>
|
||||
/// <param name="message">The message to be send</param>
|
||||
/// <returns></returns>
|
||||
protected abstract byte[] EncodeBody<T> (T message);
|
||||
}
|
||||
}
|
||||
47
Server Dashboard Socket/Protocol/XmlMessageProtocol.cs
Normal file
47
Server Dashboard Socket/Protocol/XmlMessageProtocol.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Server_Dashboard_Socket {
|
||||
/// <summary>
|
||||
/// Xml serialize class
|
||||
/// </summary>
|
||||
public class XmlMessageProtocol : Protocol<XDocument> {
|
||||
/// <summary>
|
||||
/// Decodes the message from byte[] to XDocument
|
||||
/// </summary>
|
||||
/// <param name="message">The message to decode</param>
|
||||
/// <returns>Message as XDocument</returns>
|
||||
protected override XDocument Decode(byte[] message) {
|
||||
//Reads the data as utf8 string
|
||||
var xmlData = Encoding.UTF8.GetString(message);
|
||||
//Creates a new reader
|
||||
var xmlReader = XmlReader.Create(new StringReader(xmlData), new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore });
|
||||
//Decodes the data to XDocument format
|
||||
return XDocument.Load(xmlReader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode the XDocument to byte[]
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Message type e.g. object or string</typeparam>
|
||||
/// <param name="message">The message to encode</param>
|
||||
/// <returns>Message as byte[]</returns>
|
||||
protected override byte[] EncodeBody<T>(T message) {
|
||||
//new string builder
|
||||
StringBuilder sb = new StringBuilder();
|
||||
//New string writer with the string builder
|
||||
StringWriter sw = new StringWriter(sb);
|
||||
//new xml serializer with the same type as the message
|
||||
XmlSerializer xs = new XmlSerializer(typeof(T));
|
||||
//Serialize the message to a regular string
|
||||
xs.Serialize(sw, message);
|
||||
//Return as UTF8 encoded byte array
|
||||
return Encoding.UTF8.GetBytes(sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,8 @@
|
||||
<RootNamespace>Server_Dashboard_Socket</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -7,9 +7,20 @@
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v3.1": {
|
||||
"Server Dashboard Socket/1.0.0": {
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": "13.0.1"
|
||||
},
|
||||
"runtime": {
|
||||
"Server Dashboard Socket.dll": {}
|
||||
}
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||
"assemblyVersion": "13.0.0.0",
|
||||
"fileVersion": "13.0.1.25517"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -18,6 +29,13 @@
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||
"path": "newtonsoft.json/13.0.1",
|
||||
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
40cb88c995736b43b2440aaa34383fa2c95563ea
|
||||
8966ab4db41ed1e711f8adec4e833a86df6a665c
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -43,6 +43,12 @@
|
||||
"frameworks": {
|
||||
"netcoreapp3.1": {
|
||||
"targetAlias": "netcoreapp3.1",
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": {
|
||||
"target": "Package",
|
||||
"version": "[13.0.1, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
|
||||
@@ -1,11 +1,51 @@
|
||||
{
|
||||
"version": 3,
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v3.1": {}
|
||||
".NETCoreApp,Version=v3.1": {
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"type": "package",
|
||||
"compile": {
|
||||
"lib/netstandard2.0/Newtonsoft.Json.dll": {}
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Newtonsoft.Json.dll": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"sha512": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||
"type": "package",
|
||||
"path": "newtonsoft.json/13.0.1",
|
||||
"files": [
|
||||
".nupkg.metadata",
|
||||
".signature.p7s",
|
||||
"LICENSE.md",
|
||||
"lib/net20/Newtonsoft.Json.dll",
|
||||
"lib/net20/Newtonsoft.Json.xml",
|
||||
"lib/net35/Newtonsoft.Json.dll",
|
||||
"lib/net35/Newtonsoft.Json.xml",
|
||||
"lib/net40/Newtonsoft.Json.dll",
|
||||
"lib/net40/Newtonsoft.Json.xml",
|
||||
"lib/net45/Newtonsoft.Json.dll",
|
||||
"lib/net45/Newtonsoft.Json.xml",
|
||||
"lib/netstandard1.0/Newtonsoft.Json.dll",
|
||||
"lib/netstandard1.0/Newtonsoft.Json.xml",
|
||||
"lib/netstandard1.3/Newtonsoft.Json.dll",
|
||||
"lib/netstandard1.3/Newtonsoft.Json.xml",
|
||||
"lib/netstandard2.0/Newtonsoft.Json.dll",
|
||||
"lib/netstandard2.0/Newtonsoft.Json.xml",
|
||||
"newtonsoft.json.13.0.1.nupkg.sha512",
|
||||
"newtonsoft.json.nuspec",
|
||||
"packageIcon.png"
|
||||
]
|
||||
}
|
||||
},
|
||||
"libraries": {},
|
||||
"projectFileDependencyGroups": {
|
||||
".NETCoreApp,Version=v3.1": []
|
||||
".NETCoreApp,Version=v3.1": [
|
||||
"Newtonsoft.Json >= 13.0.1"
|
||||
]
|
||||
},
|
||||
"packageFolders": {
|
||||
"C:\\Users\\Crylia\\.nuget\\packages\\": {},
|
||||
@@ -50,6 +90,12 @@
|
||||
"frameworks": {
|
||||
"netcoreapp3.1": {
|
||||
"targetAlias": "netcoreapp3.1",
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": {
|
||||
"target": "Package",
|
||||
"version": "[13.0.1, )"
|
||||
}
|
||||
},
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{
|
||||
"version": 2,
|
||||
"dgSpecHash": "TThsag+xtSY7ctBsPwAhUX7uLjuhld1ipCW1nP987HRzxMfYvczqncYfdca/U4IfbiniWP3eJFeh7yA09+/gGA==",
|
||||
"dgSpecHash": "l9ApM4rx/nIquK7TUSE2VVfvhwnQ4+tycTwd5vMzM9v+MhFzGIKE8eVwCEj+r8Oe9Orh3cE/LeZlJ+t9G9ZaSg==",
|
||||
"success": true,
|
||||
"projectFilePath": "C:\\Users\\Crylia\\Documents\\Git\\Server Dashboard\\Server Dashboard Socket\\Server Dashboard Socket.csproj",
|
||||
"expectedPackageFiles": [],
|
||||
"expectedPackageFiles": [
|
||||
"C:\\Users\\Crylia\\.nuget\\packages\\newtonsoft.json\\13.0.1\\newtonsoft.json.13.0.1.nupkg.sha512"
|
||||
],
|
||||
"logs": []
|
||||
}
|
||||
Reference in New Issue
Block a user