Refactoring NatsPublisher. DIing IOptions is potentially a bad decision - c#

I made a wrapper for the NATS Client which basically adds ASP.NET DI functionality. There are two "issues" that I think should be fixed.
I think _jetStream should be lazy loaded.
Lazy initialization is usually used whereby you only load or initialize an object when you first need it.
_jetStreamFactory = new Lazy<IJetStream>(() => connection.CreateJetStreamContext());
The library is meant to extend ConnectionFactory's capabilities with additional configuration options (Decorator pattern). Knowing that, I don't think it's appropriate to dependency inject IOptions<NatsProducerConfiguration> in the NatsPublisher class because it violates the main idea.
If there is anything else
The code that the question is about
public class ProducerConfiguration
{
public string[]? Servers { get; init; }
public string? Url { get; init; }
public string? User { get; init; }
public string? Password { get; init; }
public required string Stream { get; init; }
public required string Subject { get; init; }
}
public interface IPublisher
{
ValueTask<PublishAck> Publish<T>(T payload) where T : class;
ValueTask<PublishAck> PublishAsync(byte[] payload, IEnumerable<(string, string)> headers);
ValueTask<PublishAck> PublishWithDeduplicationIdAsync(byte[] payload, string id);
}
public sealed class NatsPublisher : IPublisher
{
private readonly ProducerConfiguration _configuration;
private readonly IJetStream _jetStream;
public NatsPublisher(IOptions<ProducerConfiguration> options, IConnection connection)
{
_configuration = options.Value;
JetStreamUtils.CreateStreamOrUpdateSubjects(connection, _configuration.Stream, _configuration.Subject);
_jetStream = connection.CreateJetStreamContext();
}
public async ValueTask<PublishAck> Publish<T>(T payload)
where T : class
{
var data = JsonSerializer.SerializeToUtf8Bytes(payload);
var msg = new Msg(_configuration.Subject, null, null, data);
return await _jetStream.PublishAsync(msg);
}
public async ValueTask<PublishAck> PublishAsync(byte[] payload)
{
var msg = new Msg(_configuration.Subject, null, null, payload);
return await _jetStream.PublishAsync(msg);
}
public async ValueTask<PublishAck> PublishAsync(byte[] payload, IEnumerable<(string, string)> headers)
{
var msg = new Msg(_configuration.Subject, null, null, payload);
foreach (var (header, val) in headers)
{
msg.Header[header] = val;
}
return await _jetStream.PublishAsync(msg);
}
public async ValueTask<PublishAck> PublishWithDeduplicationIdAsync(byte[] payload, string id)
{
var msg = new Msg(_configuration.Subject, null, null, payload)
{
Header = { ["Nats-Msg-Id"] = id }
};
return await _jetStream.PublishAsync(msg);
}
}
The library itself
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddNatsClient(
this IServiceCollection services,
Action<Options>? configureOptions = null,
ServiceLifetime connectionServiceLifeTime = ServiceLifetime.Transient)
{
ArgumentNullException.ThrowIfNull(services);
var defaultOptions = ConnectionFactory.GetDefaultOptions();
configureOptions?.Invoke(defaultOptions);
services.AddSingleton(defaultOptions);
services.AddSingleton<ConnectionFactory>();
services.AddSingleton<INatsClientConnectionFactory, NatsClientConnectionFactoryDecorator>();
services.TryAdd(new ServiceDescriptor(typeof(IConnection), provider =>
{
var options = provider.GetRequiredService<Options>();
var connectionFactory = provider.GetRequiredService<INatsClientConnectionFactory>();
return connectionFactory.CreateConnection(options);
}, connectionServiceLifeTime));
services.TryAdd(new ServiceDescriptor(typeof(IEncodedConnection), provider =>
{
var options = provider.GetRequiredService<Options>();
var connectionFactory = provider.GetRequiredService<INatsClientConnectionFactory>();
return connectionFactory.CreateEncodedConnection(options);
}, connectionServiceLifeTime));
return services;
}
}
public interface INatsClientConnectionFactory
{
IConnection CreateConnection(Action<Options>? configureOptions = null);
IConnection CreateConnection(Options options);
IEncodedConnection CreateEncodedConnection(Action<Options>? configureOptions = null);
IEncodedConnection CreateEncodedConnection(Options options);
}
public sealed class NatsClientConnectionFactoryDecorator : INatsClientConnectionFactory
{
private readonly ConnectionFactory _connectionFactory;
public NatsClientConnectionFactoryDecorator(ConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public IConnection CreateConnection(Action<Options>? configureOptions = default)
{
var options = ConnectionFactory.GetDefaultOptions();
configureOptions?.Invoke(options);
return CreateConnection(options);
}
public IConnection CreateConnection(Options options)
{
return _connectionFactory.CreateConnection(options);
}
public IEncodedConnection CreateEncodedConnection(Action<Options>? configureOptions = default)
{
var options = ConnectionFactory.GetDefaultOptions();
configureOptions?.Invoke(options);
return CreateEncodedConnection(options);
}
public IEncodedConnection CreateEncodedConnection(Options options)
{
return _connectionFactory.CreateEncodedConnection(options);
}
}
public static class JetStreamUtils
{
// ----------------------------------------------------------------------------------------------------
// STREAM INFO / CREATE / UPDATE
// ----------------------------------------------------------------------------------------------------
public static StreamInfo? GetStreamInfoOrNullWhenNotExist(IJetStreamManagement jsm, string streamName)
{
try
{
return jsm.GetStreamInfo(streamName);
}
catch (NATSJetStreamException e)
{
if (e.ErrorCode == 404)
{
return null;
}
throw;
}
}
public static bool StreamExists(IConnection c, string streamName)
{
return GetStreamInfoOrNullWhenNotExist(c.CreateJetStreamManagementContext(), streamName) != null;
}
public static bool StreamExists(IJetStreamManagement jsm, string streamName)
{
return GetStreamInfoOrNullWhenNotExist(jsm, streamName) != null;
}
public static void ExitIfStreamExists(IJetStreamManagement jsm, string streamName)
{
if (StreamExists(jsm, streamName))
{
Environment.Exit(-1);
}
}
public static void ExitIfStreamNotExists(IConnection c, string streamName)
{
if (!StreamExists(c, streamName))
{
Environment.Exit(-1);
}
}
public static StreamInfo CreateStream(IJetStreamManagement jsm, string streamName, StorageType storageType,
params string[] subjects)
{
var sc = StreamConfiguration.Builder()
.WithName(streamName)
.WithStorageType(storageType)
.WithSubjects(subjects)
.Build();
var si = jsm.AddStream(sc);
return si;
}
public static StreamInfo CreateStream(IJetStreamManagement jsm, string stream, params string[] subjects)
{
return CreateStream(jsm, stream, StorageType.Memory, subjects);
}
public static StreamInfo CreateStream(IConnection c, string stream, params string[] subjects)
{
return CreateStream(c.CreateJetStreamManagementContext(), stream, StorageType.Memory, subjects);
}
public static StreamInfo CreateStreamExitWhenExists(IConnection c, string streamName, params string[] subjects)
{
return CreateStreamExitWhenExists(c.CreateJetStreamManagementContext(), streamName, subjects);
}
public static StreamInfo CreateStreamExitWhenExists(IJetStreamManagement jsm, string streamName,
params string[] subjects)
{
ExitIfStreamExists(jsm, streamName);
return CreateStream(jsm, streamName, StorageType.Memory, subjects);
}
public static void CreateStreamWhenDoesNotExist(IJetStreamManagement jsm, string stream, params string[] subjects)
{
try
{
jsm.GetStreamInfo(stream);
return;
}
catch (NATSJetStreamException)
{
}
var sc = StreamConfiguration.Builder()
.WithName(stream)
.WithStorageType(StorageType.Memory)
.WithSubjects(subjects)
.Build();
jsm.AddStream(sc);
}
public static void CreateStreamWhenDoesNotExist(IConnection c, string stream, params string[] subjects)
{
CreateStreamWhenDoesNotExist(c.CreateJetStreamManagementContext(), stream, subjects);
}
public static StreamInfo CreateStreamOrUpdateSubjects(IJetStreamManagement jsm, string streamName,
StorageType storageType, params string[] subjects)
{
var si = GetStreamInfoOrNullWhenNotExist(jsm, streamName);
if (si == null)
{
return CreateStream(jsm, streamName, storageType, subjects);
}
var sc = si.Config;
var needToUpdate = false;
foreach (var sub in subjects)
{
if (!sc.Subjects.Contains(sub))
{
needToUpdate = true;
sc.Subjects.Add(sub);
}
}
if (needToUpdate)
{
si = jsm.UpdateStream(sc);
}
return si;
}
public static StreamInfo CreateStreamOrUpdateSubjects(IJetStreamManagement jsm, string streamName,
params string[] subjects)
{
return CreateStreamOrUpdateSubjects(jsm, streamName, StorageType.Memory, subjects);
}
public static StreamInfo CreateStreamOrUpdateSubjects(IConnection c, string stream, params string[] subjects)
{
return CreateStreamOrUpdateSubjects(c.CreateJetStreamManagementContext(), stream, StorageType.Memory,
subjects);
}
// ----------------------------------------------------------------------------------------------------
// PUBLISH
// ----------------------------------------------------------------------------------------------------
public static void Publish(IConnection c, string subject, int count)
{
Publish(c.CreateJetStreamContext(), subject, "data", count);
}
public static void Publish(IJetStream js, string subject, int count)
{
Publish(js, subject, "data", count);
}
public static void Publish(IJetStream js, string subject, string prefix, int count)
{
for (var x = 1; x <= count; x++)
{
var data = prefix + x;
js.Publish(subject, Encoding.UTF8.GetBytes(data));
}
}
public static void PublishInBackground(IJetStream js, string subject, string prefix, int count)
{
new Thread(() =>
{
try
{
for (var x = 1; x <= count; x++)
{
js.Publish(subject, Encoding.ASCII.GetBytes(prefix + "-" + x));
}
}
catch (Exception)
{
Environment.Exit(-1);
}
}).Start();
Thread.Sleep(100); // give the publish thread a little time to get going
}
// ----------------------------------------------------------------------------------------------------
// READ MESSAGES
// ----------------------------------------------------------------------------------------------------
public static IList<Msg> ReadMessagesAck(ISyncSubscription sub, int timeout = 1000)
{
IList<Msg> messages = new List<Msg>();
var keepGoing = true;
while (keepGoing)
{
try
{
var msg = sub.NextMessage(timeout);
messages.Add(msg);
msg.Ack();
}
catch (NATSTimeoutException)
{
keepGoing = false;
}
}
return messages;
}
}
How to use
builder.Services.Configure<NatsProducerConfiguration>(options =>
builder.Configuration.GetSection("Nats").Bind(options));
var natsConfiguration = builder.Configuration.GetSection("Nats").Get<NatsProducerConfiguration>();
builder.Services.AddNatsClient(options =>
{
options.Servers = natsConfiguration?.Servers;
options.Url = natsConfiguration?.Url;
options.User = natsConfiguration?.User;
options.Password = natsConfiguration?.Password;
options.MaxReconnect = 5;
options.ReconnectWait = 5000;
});

Hopefully CreateStreamWhenDoesNotExist does what it says. By the way, JetStreamUtils was taken from the official C# NATS Client Samples.
I believe this fixes the pitfalls I described.
Perhaps you got a better idea?
public interface INatsPublisher
{
ValueTask PublishAsync<T>(string stream, string subject, T message) where T : class;
ValueTask PublishAsync<T>(string stream, string subject, T message, IEnumerable<(string, string)> headers)
where T : class;
ValueTask PublishDeduplicationIdAsync<T>(string stream, string subject, T message, string id)
where T : class;
}
public sealed class NatsPublisher : INatsPublisher
{
private readonly IConnection _connection;
private readonly Lazy<IJetStream> _jetStreamFactory;
public NatsPublisher(IConnection connection)
{
_connection = connection;
_jetStreamFactory = new Lazy<IJetStream>(() => connection.CreateJetStreamContext());
}
private IJetStream JetStream => _jetStreamFactory.Value;
public async ValueTask PublishAsync<T>(string stream, string subject, T message) where T : class
{
JetStreamUtils.CreateStreamOrUpdateSubjects(_connection, stream, subject);
var payload = JsonSerializer.SerializeToUtf8Bytes(message);
var msg = new Msg(subject, null, null, payload);
await JetStream.PublishAsync(msg);
}
public async ValueTask PublishAsync<T>(string stream, string subject, T message, IEnumerable<(string, string)> headers)
where T : class
{
JetStreamUtils.CreateStreamOrUpdateSubjects(_connection, stream, subject);
var payload = JsonSerializer.SerializeToUtf8Bytes(message);
var msg = new Msg(subject, null, null, payload);
foreach (var (header, val) in headers)
{
msg.Header[header] = val;
}
await JetStream.PublishAsync(msg);
}
public async ValueTask PublishDeduplicationIdAsync<T>(string stream, string subject, T message, string id)
where T : class
{
JetStreamUtils.CreateStreamOrUpdateSubjects(_connection, stream, subject);
var payload = JsonSerializer.SerializeToUtf8Bytes(message);
var msg = new Msg(subject, null, null, payload)
{
Header = { ["Nats-Msg-Id"] = id }
};
await JetStream.PublishAsync(msg);
}
}

Related

How do I trim zeros at the end of a custom ReadOnlySequence implementation?

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 .

Objective-c (c#): calling (void) method while -init

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.

How to get all items from a specific type in CosmosDB

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();
}

c# using other class method

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();
}

Why Json serializable types must have a public, parameterless constructor?

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; }
}

Categories

Resources