The web socket server expects JSON strings. _webSocket.SendAsync sends ReadOnlyMemory<byte>. The issue is that sequence.First has trailing zeros. It results in an invalid JSON message because of the trailing zeros. The question is how do I trim them?
Usage
var request = new JsonRpcRequest<object>
{
JsonRpc = "2.0",
Id = 1,
Method = "public/get_instruments",
Params = #params
};
var message = JsonSerializer.Serialize(request);
using var buffer = MemoryPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(message));
Encoding.UTF8.GetEncoder().Convert(message, buffer.Memory.Span, true, out _, out _, out _);
var seq = new OwnedMemorySequence<byte>();
seq.Append(buffer);
var msg = new ChannelWebSocket.Message
{
MessageType = WebSocketMessageType.Text,
Payload = seq
};
await client.Output.WriteAsync(msg).ConfigureAwait(false);
Code
private async Task OutputLoopAsync(CancellationToken cancellationToken)
{
await foreach (var message in _output.Reader.ReadAllAsync())
{
var sequence = message.Payload.ReadOnlySequence;
if (sequence.IsEmpty)
continue;
while (!sequence.IsSingleSegment)
{
await _webSocket.SendAsync(sequence.First, message.MessageType, false, cancellationToken);
sequence = sequence.Slice(sequence.First.Length);
}
await _webSocket.SendAsync(sequence.First, message.MessageType, true, cancellationToken);
message.Payload.Dispose();
}
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, cancellationToken);
}
public sealed class Message
{
public WebSocketMessageType MessageType { get; set; }
public OwnedMemorySequence<byte> Payload { get; set; } = null!;
}
public sealed class OwnedMemorySequence<T> : IDisposable
{
private readonly CollectionDisposable _disposable = new();
private readonly MemorySequence<T> _sequence = new();
public ReadOnlySequence<T> ReadOnlySequence => _sequence.ReadOnlySequence;
public OwnedMemorySequence<T> Append(IMemoryOwner<T> memoryOwner)
{
_disposable.Add(memoryOwner);
_sequence.Append(memoryOwner.Memory);
return this;
}
public ReadOnlySequence<T> CreateReadOnlySequence(int firstBufferStartIndex, int lastBufferEndIndex)
{
return _sequence.CreateReadOnlySequence(firstBufferStartIndex, lastBufferEndIndex);
}
public void Dispose()
{
_disposable.Dispose();
}
}
public static class MemoryOwnerSliceExtensions
{
public static IMemoryOwner<T> Slice<T>(this IMemoryOwner<T> owner, int start, int length)
{
if (start == 0 && length == owner.Memory.Length)
return owner;
return new SliceOwner<T>(owner, start, length);
}
public static IMemoryOwner<T> Slice<T>(this IMemoryOwner<T> owner, int start)
{
if (start == 0)
return owner;
return new SliceOwner<T>(owner, start);
}
private sealed class SliceOwner<T> : IMemoryOwner<T>
{
private readonly IMemoryOwner<T> _owner;
public SliceOwner(IMemoryOwner<T> owner, int start, int length)
{
_owner = owner;
Memory = _owner.Memory.Slice(start, length);
}
public SliceOwner(IMemoryOwner<T> owner, int start)
{
_owner = owner;
Memory = _owner.Memory[start..];
}
public Memory<T> Memory { get; }
public void Dispose()
{
_owner.Dispose();
}
}
}
public sealed class MemorySequence<T>
{
private MemorySegment? _head;
private MemorySegment? _tail;
public ReadOnlySequence<T> ReadOnlySequence => CreateReadOnlySequence(0, _tail?.Memory.Length ?? 0);
public MemorySequence<T> Append(ReadOnlyMemory<T> buffer)
{
if (_tail == null)
_head = _tail = new MemorySegment(buffer, 0);
else
_tail = _tail.Append(buffer);
return this;
}
public ReadOnlySequence<T> CreateReadOnlySequence(int firstBufferStartIndex, int lastBufferEndIndex)
{
return _tail == null ? new ReadOnlySequence<T>(Array.Empty<T>()) : new ReadOnlySequence<T>(_head!, firstBufferStartIndex, _tail, lastBufferEndIndex);
}
private sealed class MemorySegment : ReadOnlySequenceSegment<T>
{
public MemorySegment(ReadOnlyMemory<T> memory, long runningIndex)
{
Memory = memory;
RunningIndex = runningIndex;
}
public MemorySegment Append(ReadOnlyMemory<T> nextMemory)
{
var next = new MemorySegment(nextMemory, RunningIndex + Memory.Length);
Next = next;
return next;
}
}
}
You don't need to trim. You just need to slice your memory accordingly.
Pay attention to MemoryPool<T>.Rent (quote from the doc) returning "[...] a memory block capable capable of holding at least minBufferSize elements of T." The important bit here is "at least", meaning the returned memory is allowed to be larger than the requested size.
All you need to do is to create a slice of the requested size from the memory if it happens to be larger than the requested size before adding it to OwnedMemorySequence<T>_sequence member .
I'm trying to rewrite C# code to equivalent objective-c code and get some kind of trouble with called void function inside of -init method.
There are two constructors in C# code, one of them calls void method with different params. I've no idea how to deal with it in objective-c (feels like a novice). I will gladly accept any advice!
C# class:
namespace Translation
{
public class Adapter
{
private readonly int dirId;
private readonly string serviceUrl;
private readonly string clientName;
private readonly string clientSecret;
private static Ticket _ticket = null;
private static object _ticketSync = new object();
public Adapter(int dirId, string configUrl)
{
this.dirId = dirId;
string[] directions;
//method i'm trying to call
GetConfigInfo(configUrl, out serviceUrl, out clientName, out clientSecret, out directions);
}
public Adapter(int dirId, string serviceUrl, string clientName, string clientSecret)
{
this.dirId = dirId;
this.serviceUrl = serviceUrl;
this.clientName = clientName;
this.clientSecret = clientSecret;
}
public static void GetConfigInfo(string configUrl,
out string serviceUrl, out string clientName, out string clientSecret, out string[] directions)
{
var configXml = new XmlDocument();
using (var client = new WebClient())
{
client.Credentials = new NetworkCredential("tests", "test");
var xml = client.DownloadString(configUrl);
configXml.LoadXml(xml);
}
serviceUrl = configXml.DocumentElement.SelectSingleNode("Url").InnerText.Trim();
clientName = configXml.DocumentElement.SelectSingleNode("Client").InnerText.Trim();
clientSecret = configXml.DocumentElement.SelectSingleNode("Secret").InnerText.Trim();
directions = configXml.DocumentElement.SelectSingleNode("Directions").InnerText.Trim().
Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
public static KeyValuePair<string, string>[] ParseTopicsInfo(string xml)
{
var topicsXml = new XmlDocument();
topicsXml.LoadXml(xml);
var result = topicsXml.SelectNodes("templates/template").OfType<XmlNode>().
Select(node =>
{
var topicId = node.SelectSingleNode("id").InnerText;
var topicName = node.SelectSingleNode("name").InnerText;
return new KeyValuePair<string, string>(topicId, topicName);
}).ToArray();
return result;
}
private Ticket CreateTicket(ServiceSoap serviceSoap)
{
if (_ticket == null || _ticket.UtcExpiredAt < DateTime.UtcNow.AddSeconds(30))
lock (_ticketSync)
if (_ticket == null || _ticket.UtcExpiredAt < DateTime.UtcNow.AddSeconds(30))
_ticket = serviceSoap.CreateTicket(clientName, clientSecret);
return _ticket;
}
public void Translate(IRanges inRanges, IRanges outRanges)
{
string text = inRanges.Text;
outRanges.OriginText = text;
bool showVariants = inRanges.Properties.GetValue(RangePropertyName.LONG_VARIANTS) != null;
bool translitUnknown = inRanges.Properties.GetValue(RangePropertyName.TRANSLIT_UNKNOWN) != null;
var topicId = (string)inRanges.Properties.GetValue(RangePropertyName.PROFILE);
using (var soap = new ServiceSoap())
{
soap.Url = serviceUrl;
var ticket = CreateTicket(soap);
outRanges.Text = soap.TranslateText(ticket.Token,
dirId.ToPrefix(), topicId, text, showVariants, translitUnknown);
}
}
public FindSamplesResult FindSamples(string topic, string text, int page, int pageSize, string contains, int flags)
{
using (var soap = new ServiceSoap())
{
soap.Url = serviceUrl;
var ticket = CreateTicket(soap);
return soap.FindSamples(ticket.Token,
dirId.ToPrefix(), topic, text, page, pageSize, contains, flags, System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName);
}
}
public KeyValuePairSOfStringInt32[] GetSampleStats(string text)
{
using (var soap = new ServiceSoap())
{
soap.Url = serviceUrl;
var ticket = CreateTicket(soap);
return soap.GetSampleStats(ticket.Token,
dirId.ToPrefix(), text);
}
}
public string GetTranslateSiteUrl(string url, string topic)
{
using (var soap = new ServiceSoap())
{
soap.Url = serviceUrl;
var ticket = CreateTicket(soap);
return soap.GetTranslateSiteUrl(ticket.Token,
dirId.ToPrefix(), topic, url, System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName);
}
}
public string GetDirections()
{
using (var soap = new ServiceSoap())
{
soap.Url = serviceUrl;
var ticket = CreateTicket(soap);
return soap.GetDirectionsFor(ticket.Token, "text");
}
}
public string DetectLanguage(string text)
{
using (var soap = new ServiceSoap())
{
soap.Url = serviceUrl;
var ticket = CreateTicket(soap);
return soap.AutoDetectLang(ticket.Token, text);
}
}
public GetEdInfoOrTranslateTextResult GetEdInfoOrTranslateText(string topic, string text)
{
using (var soap = new ServiceSoap())
{
soap.Url = serviceUrl;
var ticket = CreateTicket(soap);
return soap.GetEdInfoOrTranslateText(ticket.Token,
dirId.ToPrefix(), topic, text, System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName);
}
}
public KeyValuePair<string, string>[] GetTopics()
{
using (var soap = new ServiceSoap())
{
soap.Url = serviceUrl;
var ticket = CreateTicket(soap);
return ParseTopicsInfo(soap.GetTopics(ticket.Token, System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName));
}
}
#region Not implemented
public void Initialize(string dirsPath, string k8Path, string mainClsid, int mainDirId, string mainPrefix, Data.IDictionaries dicts, object lms)
{
throw new NotImplementedException();
}
public string TranslateWord(string text, object flags)
{
throw new NotImplementedException();
}
public void Parse(IRanges inRanges, IRanges outRanges)
{
throw new NotImplementedException();
}
public void ParseToRangesMorphologizator(IRanges inRanges, IRanges outRanges)
{
throw new NotImplementedException();
}
public void ParseToRangesMorphologizatorAfterHR(IRanges inRanges, IRanges outRanges)
{
throw new NotImplementedException();
}
#endregion
[WebServiceBindingAttribute(Name = "test1", Namespace = "http://api.test.test/")]
public class ServiceSoap : SoapHttpClientProtocol
{
public new string Url
{
get
{
return base.Url;
}
set
{
base.Url = value;
base.UseDefaultCredentials = IsLocalFileSystemWebService(value);
}
}
[SoapDocumentMethodAttribute("http://api.test.test/CreateTicket")]
public Ticket CreateTicket(string ClientName, string ClientSecret)
{
var results = this.Invoke("CreateTicket", new object[]
{
ClientName,
ClientSecret
});
return (Ticket)results[0];
}
[SoapDocumentMethodAttribute("http://api.test.test/GetDirectionsFor")]
public string GetDirectionsFor(string Token, string For)
{
var results = this.Invoke("GetDirectionsFor", new object[]
{
Token,
For
});
return (string)results[0];
}
[SoapDocumentMethodAttribute("http://api.test.test/GetTopics")]
public string GetTopics(string Token, string Lang)
{
var results = this.Invoke("GetTopics", new object[]
{
Token,
Lang
});
return (string)results[0];
}
[SoapDocumentMethodAttribute("http://api.test.test/TranslateText")]
public string TranslateText(string Token, string DirCode, string TplId, string Text, bool ShowVariants, bool TranslitUnknown)
{
var results = this.Invoke("TranslateText", new object[]
{
Token,
DirCode,
TplId,
Text,
ShowVariants,
TranslitUnknown
});
return (string)results[0];
}
[SoapDocumentMethodAttribute("http://api.test.test/GetEdInfoOrTranslateText")]
public GetEdInfoOrTranslateTextResult GetEdInfoOrTranslateText(string Token, string DirCode, string TplId, string Text, string Lang)
{
var results = this.Invoke("GetEdInfoOrTranslateText", new object[]
{
Token,
DirCode,
TplId,
Text,
Lang
});
return (GetEdInfoOrTranslateTextResult)results[0];
}
[SoapDocumentMethodAttribute("http://api.test.test/AutoDetectLang")]
public string AutoDetectLang(string Token, string Text)
{
var results = this.Invoke("AutoDetectLang", new object[]
{
Token,
Text
});
return (string)results[0];
}
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://api.test.test/FindSamples", RequestNamespace = "http://api.test.test/", ResponseNamespace = "http://api.test.test/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public FindSamplesResult FindSamples(string Token, string DirCode, string Topic, string Text, int Page, int PageSize, string Contains, int Flags, string Lang)
{
object[] results = this.Invoke("FindSamples", new object[] {
Token,
DirCode,
Topic,
Text,
Page,
PageSize,
Contains,
Flags,
Lang});
return ((FindSamplesResult)(results[0]));
}
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://api.test.test/GetSampleStats", RequestNamespace = "http://api.test.test/", ResponseNamespace = "http://api.test.test/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public KeyValuePairSOfStringInt32[] GetSampleStats(string Token, string DirCode, string Text)
{
object[] results = this.Invoke("GetSampleStats", new object[] {
Token,
DirCode,
Text
});
return ((KeyValuePairSOfStringInt32[])(results[0]));
}
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://api.test.test/GetTranslateSiteUrl", RequestNamespace = "http://api.test.test/", ResponseNamespace = "http://api.test.test/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string GetTranslateSiteUrl(string Token, string DirCode, string TopicId, string URL, string Lang)
{
object[] results = this.Invoke("GetTranslateSiteUrl", new object[] {
Token,
DirCode,
TopicId,
URL,
Lang
});
return (string)results[0];
}
private static bool IsLocalFileSystemWebService(string url)
{
if (string.IsNullOrEmpty(url))
return false;
var wsUri = new Uri(url);
if (wsUri.Port >= 1024 && string.Equals(wsUri.Host, "localhost", StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
}
[XmlTypeAttribute(Namespace = "http://api.test.test/")]
public class Ticket
{
public string Token;
public DateTime UtcExpiredAt;
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://api.test.test/")]
public partial class SampleRun
{
private int positionField;
private int lengthField;
/// <remarks/>
public int Position
{
get
{
return this.positionField;
}
set
{
this.positionField = value;
}
}
/// <remarks/>
public int Length
{
get
{
return this.lengthField;
}
set
{
this.lengthField = value;
}
}
}
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://api.test.test/")]
public partial class Sample
{
private string corpusIdField;
private string sourceField;
private string translationField;
private SampleRun[] sourceRunsField;
private SampleRun[] translationRunsField;
/// <remarks/>
public string CorpusId
{
get
{
return this.corpusIdField;
}
set
{
this.corpusIdField = value;
}
}
/// <remarks/>
public string Source
{
get
{
return this.sourceField;
}
set
{
this.sourceField = value;
}
}
/// <remarks/>
public string Translation
{
get
{
return this.translationField;
}
set
{
this.translationField = value;
}
}
/// <remarks/>
public SampleRun[] SourceRuns
{
get
{
return this.sourceRunsField;
}
set
{
this.sourceRunsField = value;
}
}
/// <remarks/>
public SampleRun[] TranslationRuns
{
get
{
return this.translationRunsField;
}
set
{
this.translationRunsField = value;
}
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://api.test.test/")]
public partial class KeyValuePairSOfStringInt32
{
private string keyField;
private int valueField;
/// <remarks/>
public string Key
{
get
{
return this.keyField;
}
set
{
this.keyField = value;
}
}
/// <remarks/>
public int Value
{
get
{
return this.valueField;
}
set
{
this.valueField = value;
}
}
}
#region Samples
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://api.test.test/")]
public partial class GetSampleStatsResult
{
private KeyValuePairSOfStringInt32[] translationsField;
public KeyValuePairSOfStringInt32[] Translations
{
get
{
return this.translationsField;
}
set
{
this.translationsField = value;
}
}
}
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://api.test.test/")]
public partial class FindSamplesResult
{
private int totalsField;
private Sample[] samplesField;
private KeyValuePairSOfStringInt32[] corpusesField;
/// <remarks/>
public int Totals
{
get
{
return this.totalsField;
}
set
{
this.totalsField = value;
}
}
/// <remarks/>
public Sample[] Samples
{
get
{
return this.samplesField;
}
set
{
this.samplesField = value;
}
}
/// <remarks/>
public KeyValuePairSOfStringInt32[] Corpuses
{
get
{
return this.corpusesField;
}
set
{
this.corpusesField = value;
}
}
}
#endregion
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://api.test.test/")]
public partial class GetEdInfoOrTranslateTextResult
{
public string ResultType { get; set; }
public string ResultText { get; set; }
}
}
}
Objective-c .h:
#interface Ticket : NSObject
{
NSString* token;
NSDate* dateTimeUtcExpiredAt;
}
#end
#interface SampleRun : NSObject
#property int* position;
#property int* length;
#end
#interface Sample : NSObject
#property NSString* corpusId;
#property NSString* source;
#property NSString* translation;
#property SampleRun* SourceRuns;
#property SampleRun* TranslationRuns;
#end
#interface KeyValuePairsOfStringInt32
#property int* totals;
#property Sample* samples;
#property KeyValuePairsOfStringInt32* corpuses;
#end
#interface GetEdInfoOrTranslateTextResult
#property NSString* resultType;
#property NSString* resultText;
#end
#interface Adapter : NSObject
{
Ticket* _ticket;
NSObject* _ticketSync;
}
#property int* dirId;
#property NSString* serviceUrl;
#property NSString* clientName;
#property NSString* clientSecret;
-(void)getConfigInfoWithConfigUrl: (NSString*) _configUrl AndServiceUrl: (NSString*) _servireUrl AndClientName: (NSString*) _clientName AndClientSecret: (NSString*) _clinetSecret AndDirections: (NSArray*) directions;
#end
Objective-c .mm:
#implementation Adapter
- (id) initWithDirId: (int*) _dirId AndConfigUrl: (NSString*) _configUrl;
{
self = [super init];
if (self) {
self.dirId = _dirId;
NSString* directions;
//here is calling (there are more params ofc)
// but i can't figure it out how to do it in the right way
[self getConfigInfoWithConfigUrl: _configUrl
AndServiceUrl: _servireUrl AndClientName: _clientName
AndClientSecret: _clinetSecret AndDirections: directions];
}
return self;
}
- (id) initBase:(int*) _dirId AndServiceUrl: (NSString*) _serviceUrl AndClientName: (NSString*) _clientName AndClientSecret: (NSString*) _clientSecret;
{
self = [super init];
if (self) {
self.dirId = _dirId;
self.serviceUrl = _serviceUrl;
self.clientName = _clientName;
self.clientSecret = _clientSecret;
}
return self;
}
#end
When I change '-(void)' to '+(void)' in .h file ("+" is like static in c#, so I've tried it first), I get:
No visible #interface for 'OnlineAdapter' declares the selector
'getConfigInfoWithConfigUrl:AndServiceUrl:AndClientName:AndClientSecret:AndDirections:'
When I call with '-(void)', I get errors:
Use of undeclared identifier '_clinetSecret';
did you mean '_clientSecret'? //etc. for other args
I guess it happens because of 'out' attr in C# code, but I'm not sure if there an analogue in obj-c.
Objective-c crashes my brain. Any help would be appreciated!
You didn't show your code for your Objective-C method getConfigInfoWithConfigUrl:AndServiceUrl:AndClientName:AndClientSecret:AndDirections:. Since your C# method GetConfigInfo was a static method, you probably want to make your Objective-C method getConfigInfoWithConfigUrl:AndServiceUrl:AndClientName:AndClientSecret:AndDirections: a class method, declared with a +: +(void) getConfigInfoWithConfigUrl: ...
Class methods will need to be called on a class object, not on an ordinary instance: [Adapter getConfigInfoWithConfigUrl: ...]
out and ref parameters in C# denote that the parameter is passed by reference. In C, we usually accomplish the equivalent thing by passing a pointer to the variable.
So it should be declared something like this:
+ (void)getConfigInfoWithConfigUrl:(NSString *)_configUrl
AndServiceUrl:(NSString **)_servireUrl
AndClientName:(NSString **)_clientName
AndClientSecret:(NSString **)_clientSecret
AndDirections:(NSArray**)directions;
And inside the method it will assign to the variables like this:
*serviceUrl = ...
*clientName = ...
*clientSecret = ...
*directions = ...
And you call it something like this:
[Adapter getConfigInfoWithConfigUrl:_configUrl
AndServiceUrl:&_servireUrl
AndClientName:&_clientName
AndClientSecret:&_clientSecret
AndDirections:&directions];
self in Objective-C is only implicit for accessing instance variables (ivars), not for method calls. So you always need to use the following syntax:
[self getConfigInfoWithConfigUrl: _configUrl];
Note that the method name has a typo in its declaration in the .h file.
The fact that you're doing this from an init… vs any other method makes no difference.
I have the following DocumentDBRepository
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Web;
namespace TenantManagementWebApi.DataAccess
{
public static class DocumentDBRepository<T> where T : class
{
private static readonly string DatabaseId = ConfigurationManager.AppSettings["database"];
private static readonly string CollectionId = ConfigurationManager.AppSettings["collection"];
private static DocumentClient client;
public static async Task<T> GetItemAsync(string id)
{
try
{
Document document = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}
public static async Task<IEnumerable<T>> GetItemsAsync(Expression<Func<T, bool>> predicate)
{
IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
new FeedOptions { MaxItemCount = -1 })
.Where(predicate)
.AsDocumentQuery();
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
public static async Task<Document> CreateItemAsync(T item)
{
return await client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
}
public static async Task<Document> UpdateItemAsync(string id, T item)
{
return await client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
}
public static async Task DeleteItemAsync(string id)
{
await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
}
public static void Initialize()
{
client = new DocumentClient(new Uri(ConfigurationManager.AppSettings["endpoint"]), ConfigurationManager.AppSettings["authKey"]);
CreateDatabaseIfNotExistsAsync().Wait();
CreateCollectionIfNotExistsAsync().Wait();
}
private static async Task CreateDatabaseIfNotExistsAsync()
{
try
{
await client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await client.CreateDatabaseAsync(new Database { Id = DatabaseId });
}
else
{
throw;
}
}
}
private static async Task CreateCollectionIfNotExistsAsync()
{
try
{
await client.ReadDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await client.CreateDocumentCollectionAsync(
UriFactory.CreateDatabaseUri(DatabaseId),
new DocumentCollection { Id = CollectionId },
new RequestOptions { OfferThroughput = 1000 });
}
else
{
throw;
}
}
}
}
}
And I need to get all items from a specific type (eg Tenant)
public class TenantController : ApiController
{
private static DocumentClient client;
public TenantController()
{
client = new DocumentClient(new Uri(ConfigurationManager.AppSettings["endpoint"]), ConfigurationManager.AppSettings["authKey"]);
}
public async Task<IQueryable<Tenant>> GetTenants()
{
return await DocumentDBRepository<IQueryable<Tenant>>.GetItemsAsync());
}
Error is obvious:
There is no argument given that corresponds to the required formal parameter 'predicate' of 'DocumentDBRepository<IQueryable<Tenant>>.GetItemsAsync(Expression<Func<IQueryabl
BUt I need to send no predicate because I want to get all items from a specific type of object:
public class Tenant
{
public string TenantId { get; set; }
public string TenantUrl { get; set; }
public string CertificatePath { get; set; }
public string CertificatePassword { get; set; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
Try this
public async Task<List<Tenant>> GetTenants()
{
return await DocumentDBRepository<Tenant>.GetItemsAsync().ToList();
}
Thanks to NHMountainGoat for an answer!
Implementing Interface looks a good choice so we have only the 'needed' method instanciated.
It looks like this now:
EDIT
class Machine
{
//REM: MachineConnexion is a link to the main server where asking the data
internal linkToPLC LinkToPLC;
public IlinkToPLC ILinkPLC;
public interface IlinkToPLC//Interface to linkPLC
{
Int16 MachineNumIS { get; set; }
}
internal class linkToPLC : IlinkToPLC
{
private Int16 Act_MachineNum;
private List<string> genlnkPLCCanvas;
private List<string> genlnkPLCworkingwith;
static private List<string> ListSymbolNoExist;
private string[] ListToPLClnk = {
"GlobalFolder.PMachine[{0}].",
"GlobalFolder.PMachine[{0}].STATE.",
"GlobalFolder.Machine[{0}].",
"GlobalFolder.Machine[{0}].STATE.",
};
public linkToPLC()//ctor
{
genlnkPLCCanvas = new List<string>(ListToPLClnk);
genlnkPLCworkingwith = new List<string>(ListToPLClnk);
ListSymbolNoExist = new List<string>();
Act_MachineNum = MachineNumIS;
}
public Int16 MachineNumIS { get { return (Int16)ReadWriteMachine("data"); } set { ReadWriteMachine("data", value); } }
public string ValueExist(string ValueToreach, bool WorkingDATA = false)
{
if (!WorkingDATA)
{
for (int inc = 0; inc < genlnkPLCworkingwith.Count; inc++)
{
string StrValueToReach = genlnkPLCworkingwith[inc] + ValueToreach;
if (MachineConnexion.SymbolExists(StrValueToReach))
{
ListSymbolNoExist.Clear();
return StrValueToReach;
}
else ListSymbolNoExist.Add(genlnkPLCworkingwith[inc] + ValueToreach);
}
}
else if (WorkingDATA)
{
string StrValueToReach = genlnkPLCworkingwith[10] + ValueToreach;
if (MachineConnexion.SymbolExists(StrValueToReach))
{
ListSymbolNoExist.Clear();
return StrValueToReach;
}
else ListSymbolNoExist.Add(genlnkPLCworkingwith[10] + ValueToreach);
}
if (ListSymbolNoExist.Count != 0)
{
string ErrorList = "";
for (int inc = 0; inc < ListSymbolNoExist.Count; inc++)
{
ErrorList = string.Concat(ErrorList + "Num: " + inc.ToString() + " " + ListSymbolNoExist[inc].ToString() + "\n");
}
Console.WriteLine("Error" + ErrorList);
}
return null;
}
public object ReadWriteMachine(string VariableName, object DataToWrite = null, bool WorkingDATA = false)
{
string valueToFind = "";
if (ValueExist(VariableName) != "FALSE")
{
if (DataToWrite != null) { MachineConnexion.WriteSymbol(valueToFind, DataToWrite); }
return MachineConnexion.ReadSymbol(valueToFind);
}
return VariableName;
}
}
public Machine() //constructor
{
LinkToPLC = new linkToPLC();
}
}
And It doesn't work telling me that the reference object is not defined to an instance of the object..... in the line : Machine() LinkToPLC = new linkToPLC();//REM I found the bug, it was me ;o)) 24112016
//REM 24112016
What are the main differences between those two concept: static Instance and Interface?
Example:
class Program
{
static void Main(string[] args)
{
ITestInterface InterInstance = new TestInterface();
//test Interface
bool value1 = true;
value1 = InterInstance.invert(value1);
InterInstance.print(value1);
//test Instance static
TestStaticInstance staticInstance = new TestStaticInstance();
staticInstance.Instance.invert(value1);
staticInstance.Instance.print(value1);
Console.ReadKey();
}
}
class TestInterface : ITestInterface
{
public bool invert(bool value)
{
return !value;
}
public void print(bool value)
{
Console.WriteLine(value.ToString()+"\n");
}
private void methodX()
{ }
}
interface ITestInterface
{
bool invert(bool value);
void print(bool value);
}
public class TestStaticInstance
{
public TestStaticInstance Instance;
public TestStaticInstance()
{
Instance = this;
}
internal bool invert(bool value)
{
return !value;
}
internal void print(bool value)
{
Console.WriteLine(value.ToString());
}
}
Thanks
Can you structure your other classes to take an instance of the link class? See:
/// <summary>
/// just a stub to demonstrate the model
/// </summary>
internal class Machine
{
public string ReadData() { return "this is data"; }
public void WriteData(string data) { Console.WriteLine(data); }
}
internal interface IMachineDataAccessor
{
string Read();
void Write(string data);
}
class LinkClass : IMachineDataAccessor
{
protected Machine _machine;
public LinkClass(Machine machine)
{
_machine = machine;
}
public void DoMyWork()
{
// insert work somewhere in here.
string dataFromMachine = Read();
Write("outbound data");
}
public string Read()
{
return _machine.ReadData();
}
public void Write(string data)
{
_machine.WriteData(data);
}
}
class PersistentClass
{
IMachineDataAccessor _machineImpl;
public PersistentClass(IMachineDataAccessor machineAccessImplementation)
{
_machineImpl = machineAccessImplementation;
}
public void DoMyWork()
{
string dataFromMachine = _machineImpl.Read();
// insert work here. Or anywhere, actually..
_machineImpl.Write("outbound data");
}
}
class StateClass
{
IMachineDataAccessor _machineImpl;
public StateClass(IMachineDataAccessor machineAccessImplementation)
{
_machineImpl = machineAccessImplementation;
}
public void DoMyWork()
{
string dataFromMachine = _machineImpl.Read();
// insert work here. Or anywhere, actually..
_machineImpl.Write("outbound data");
}
}
static void Main(string[] args)
{
LinkClass link = new LinkClass(new Machine());
PersistentClass persistent = new PersistentClass(link as IMachineDataAccessor);
StateClass state = new StateClass(link as IMachineDataAccessor);
persistent.DoMyWork();
state.DoMyWork();
link.DoMyWork();
}
I have a method which has a string type parameter and returns a List where Tasks is a class defined by me.
When I want to JSON serialize the returned List it gives me an Exception:
InvalidOperationException("Json serializable types must have a public, parameterless constructor");
What should I do?
UPDATE: Code sample added
My class looks like this:
public class Tasks
{
public int _taskReprogramat;
public int TaskReprogramat{ get; set; }
public string TaskName {get; set; }
public string Description{get; set; }
public string IntreOrele{get; set; }
public DateTime AssignDate{get; set; }
public string Status{get; set; }
public Tasks() { }
}
and I have the following classes:
public class DataContractJsonSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public DataContractJsonSerializerOperationBehavior(OperationDescription operation) : base(operation) { }
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractJsonSerializer(type);
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractJsonSerializer(type);
}
}
and
public class JsonDataContractBehaviorAttribute : Attribute, IContractBehavior
{
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
this.ReplaceSerializerOperationBehavior(contractDescription);
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
{
this.ReplaceSerializerOperationBehavior(contractDescription);
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
foreach (OperationDescription operation in contractDescription.Operations)
{
foreach (MessageDescription message in operation.Messages)
{
this.ValidateMessagePartDescription(message.Body.ReturnValue);
foreach (MessagePartDescription part in message.Body.Parts)
{
this.ValidateMessagePartDescription(part);
}
foreach (MessageHeaderDescription header in message.Headers)
{
this.ValidateJsonSerializableType(header.Type);
}
}
}
}
private void ReplaceSerializerOperationBehavior(ContractDescription contract)
{
foreach (OperationDescription od in contract.Operations)
{
for (int i = 0; i < od.Behaviors.Count; i++)
{
DataContractSerializerOperationBehavior dcsob = od.Behaviors[i] as DataContractSerializerOperationBehavior;
if (dcsob != null)
{
od.Behaviors[i] = new DataContractJsonSerializerOperationBehavior(od);
}
}
}
}
private void ValidateMessagePartDescription(MessagePartDescription part)
{
if (part != null)
{
this.ValidateJsonSerializableType(part.Type);
}
}
private void ValidateJsonSerializableType(Type type )
{
if (type != typeof(void))
{
if (!type.IsPublic)
{
throw new InvalidOperationException("Json serialization is supported in public types only");
}
ConstructorInfo defaultConstructor = type.GetConstructor(new Type[0]);
if (!type.IsPrimitive && defaultConstructor == null )
{
throw new InvalidOperationException("Json serializable types must have a public, parameterless constructor");
}
}
}
}
and my method in which I am using the Tasks class is:
public List<Tasks> GetTask(string admin, DateTime date)
{
List<Tasks> tasks = new List<Tasks>();
string conn = ConfigurationManager.ConnectionStrings["qtmConnectionString"].ConnectionString;
SqlConnection myConn = new SqlConnection(conn);
myConn.Open();
SqlCommand myCommand = new SqlCommand("tasks", myConn);
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.Parameters.Add("#username", SqlDbType.NChar);
myCommand.Parameters["#username"].Value = admin;
myCommand.Parameters.AddWithValue("#date", date);
SqlDataReader reader = myCommand.ExecuteReader();
string status = null;
string intreOrele = null;
Tasks task = new Tasks();
task.TaskName = reader[1].ToString();
task.Description = reader[2].ToString();
task.IntreOrele = intreOrele;
task.AssignDate = Convert.ToDateTime(reader[5]);
task.Status = status;
tasks.Add(task); return tasks;
}
The problem is the class you are de-serializing does not have a public, parameterless constructor. It might look like this:
public class Person
{
public Person(int id, string name)
{
this.id = id;
this.person = person;
}
private int id;
private string name;
public string Name { get { return this.name; } }
public int Id { get { return this.id; } }
}
The problem is the JSON serializer needs to do this:
var obj = new Person();
obj.Id = jsonParser.Get<int>("id");
obj.Name = jsonParser.Get<string>("name");
It isn't clever enough (or designed ) to go through the constructor like this:
var obj = new Person( jsonParser.Get<int>("id"), jsonParser.Get<string>("name") );
So change your class to do this:
public class Person
{
public Person(int id, string name)
{
this.Id = id;
this.Person = person;
}
// Parameterless constructor here
public Person()
{
}
public string Name { get ; set; }
public int Id { get;set; }
}