|
As an unbiased outsider, I saw the whole match. Well, I say unbiased, if Belgium don't improve I'm not going to win the sweepstake.
This space for rent
|
|
|
|
|
In a competition where showing you can tie your shoelaces nicely is almost enough to get you into the knock-out phase, I wouldn't worry too much just yet. It would help if you had one player who knew what that big white thing at the end of the pitch was for, though.
I am not a number. I am a ... no, wait!
|
|
|
|
|
15 month ago I was hired by my current company for a "super urgent" project.
One key requirement was that client server communication should be reliable sequential, with great control over the particular network interfaces used (wifi / 4G / IP-Radio) despite unreliable network.
I.e. the tablet is on a truck. The truck send a message about an incident inside a tunnel. While there is no network connection (inside the tunnel!). As soon as out of the tunnel the message goes and the server responds. No message should be lost, yada, yada....
Anyway.. 15 month later, it's government, they still haven't bought it (and they were secretly using another app internally, power struggle story!). Anyhow other app keeps crashing, competitor software was causing business difficulty, they throw them out and were really impressed by ours demo. Finally gonna buy it! Really like when they keep disconnecting / reconnecting network and oooo... it keeps working like nothing happened! I take great joy and pride and how this feature impress customer!
By the way I was inspired by some CP article here which suggested a single method WCF interface Send(Message) for ALL communication as a starting point (using Message subclasses, obviously). That was my starting point... (by Sacha Barber and/or Peter Hanlon ?!)
Though we didn't used WCF at all in the end...
As a side note, to share some WCF though, I see little point in WCF in fact, come to think of it... Particularly since the benefit it provides are minor when balanced against the configuration hassle it comes with and the fact that once serialization is taken care of, client server communication is no big deal...
Web API on the other hand is quite good!
Anyhow in this app we use custom communication protocol (of my creation) with TCP and.. UDP support!
First time I do an UDP server too! haha!
modified 13-Jun-16 23:07pm.
|
|
|
|
|
Well done. I hope the contract is signed.
Peter Wasser
"The whole problem with the world is that fools and fanatics are always so certain of themselves, and wiser people so full of doubts." - Bertrand Russell
|
|
|
|
|
Thanks! Me too!
Although, at this stage, it seems to be just a matter of allocating the money. Some big shot in the administration give us his blessing just this morning!
|
|
|
|
|
well done
seems like you'd be queueing/storing messages while no connection, then as soon as a connection becomes available and the queue != empty, you'd send its contents - I've oft been accused of over-engineering things, but I do know a bit about reliable data transmission
|
|
|
|
|
That's why I do indeed!
Furthermore message are queued in the database in (the unlikely ) case the app crashes. And there is a little app that check the app is alive every 5 seconds.
Oh, and also, we keep (client initiated) connection alive between client and server. This way the server can talk back to clients, since the client don't have a public well know IP available otherwise.
|
|
|
|
|
Congratulations !
cheers, Bill
«There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008
|
|
|
|
|
Thanks Bill!
Congratulation for your totally unambiguous message this time!
|
|
|
|
|
Super Lloyd wrote: 15 month later, it's government So, what the hurry?
(I'm too working on government related projects, and 15 months to make a decision - like buying hardware - sounds to me a perfectly fast response...)
Skipper: We'll fix it.
Alex: Fix it? How you gonna fix this?
Skipper: Grit, spit and a whole lotta duct tape.
|
|
|
|
|
I just have a laugh at my company who hired me for that "super urgent" project, that is all!!
|
|
|
|
|
You made the right choice for dropping WCF. I still remember the TechEd where they showed 3(ish) lines of code to host WCF... then they opened the config file!
WCF:
Make complex things possible, make simple things complex.
Web API:
An inexperience programmer can make a client in three days.... An experienced programmer can make on in ... three days. Hurray for typing client data objects manually.
Maybe Swagger (or something else) will eventually make it possible to have a decent service definition for REST APIs that can be used across languages without all that typing all the time.
Until then.... I long for the good old days of .net 1.1, where you could create a web service and corresponding client in minutes.
But of course, once we get there (again) some guy is going to say (again) "hmm, we need transactions, let's extend the protocol to support transaction flow"... and "hmm, https is very good, but we have a shared symmetric key, so let's add support for that as well"...
And down the rabbit hole we go again.
|
|
|
|
|
lmoelleb wrote: Web API:
An inexperience programmer can make a client in three days.... An experienced programmer can make on in ... three days. Hurray for typing client data objects manually.
Really that much time?!
I though 2 minute would be plenty enough!
Here is a WebAPI client helper class for ya!
public class WebQueryBuilder
{
StringBuilder url = new StringBuilder();
bool hasParam;
public WebQueryBuilder(string url)
{
this.url = new StringBuilder(url);
hasParam = url.Contains("?");
Method = HttpMethod.Get;
}
public void SetX6509Cert(byte[] rawData, string password)
{
cert = new X509Certificate2(rawData, password);
}
X509Certificate2 cert;
public string this[string key] { set { Add(key, value); } }
public void Add(string key, string value)
{
if (hasParam)
{
url.Append("&");
}
else
{
url.Append("?");
hasParam = true;
}
url.Append(WebUtility.UrlEncode(key));
url.Append("=");
url.Append(WebUtility.UrlEncode(value));
}
public void AddRange(ICollection<KeyValuePair<string, string>> headers)
{
if (headers != null)
foreach (var kv in headers)
Add(kv.Key, kv.Value);
}
public HttpMethod Method { get; set; }
public object Body { get; set; }
public WebHeaderCollection Headers
{
get
{
if (headers == null)
headers = new WebHeaderCollection();
return headers;
}
}
WebHeaderCollection headers;
public DecompressionMethods AutomaticDecompression { get; set; } = DecompressionMethods.None;
public async Task<HttpWebResponse> QueryAsync()
{
var req = (HttpWebRequest)WebRequest.CreateHttp(url.ToString());
req.Method = Method.Method;
if (headers != null)
req.Headers = Headers;
if (cert != null)
req.ClientCertificates.Add(cert);
req.AutomaticDecompression = AutomaticDecompression;
if (HttpMethod.Post.Equals(Method) || HttpMethod.Put.Equals(Method))
{
var tOs = new TaskCompletionSource<IAsyncResult>();
req.BeginGetRequestStream(x => tOs.TrySetResult(x), null);
await tOs.Task;
using (var sOut = (Stream)req.EndGetRequestStream(tOs.Task.Result))
{
if (Body != null)
{
using (var sw = new StreamWriter(sOut, Encoding.UTF8))
using (var jw = new JsonTextWriter(sw))
{
var ser = new JsonSerializer();
ser.Serialize(jw, Body);
}
req.ContentType = "application/json";
}
}
}
var tcs2 = new TaskCompletionSource<IAsyncResult>();
req.BeginGetResponse(x => tcs2.TrySetResult(x), null);
await tcs2.Task;
var wr = (HttpWebResponse)req.EndGetResponse(tcs2.Task.Result);
return wr;
}
public string Url { get { return url.ToString(); } }
public async Task<T> QueryJsonAsync<T>()
{
var wr = await QueryAsync();
ValidateResponse(wr);
return ReadResponse<T>(wr);
}
public static void ValidateResponse(HttpWebResponse wr)
{
if (wr == null)
throw new ArgumentNullException();
bool success = (int)wr.StatusCode >= 200 && (int)wr.StatusCode <= 299;
if (!success)
throw new HttpRequestException($"Problem {wr.StatusCode}: {wr.StatusDescription}");
}
public static T ReadResponse<T>(HttpWebResponse wr)
{
var sResponse = wr.GetResponseStream();
using (var sr = new StreamReader(wr.GetResponseStream()))
using (var js = new JsonTextReader(sr))
{
var ser = new JsonSerializer();
var result = ser.Deserialize<T>(js);
return result;
}
}
public static string ReadResponse(HttpWebResponse wr)
{
var sResponse = wr.GetResponseStream();
using (var sr = new StreamReader(wr.GetResponseStream()))
return sr.ReadToEnd();
}
}
|
|
|
|
|
It is not writing the code calling the API that takes the time.
It's the T on reading, and the object you have to set the body. Where do these come from? Sure, they are SIMPLE to write. But why do we in 2016 have to write simple things ourselves. Isn't that what computers are for?
|
|
|
|
|
Why not use a PCL and share the exact same T class / library on both client and server?
No need to write anything!
(or even the old fashion way, share the data exchange .cs file on both client and server app)
I am really confused why you need to write anything.....
Unless... you mean Web API written by someone else? Some third party?
Mm.... yeah I see that could be tedious.....
Someone should write a code generator for those! haha!
|
|
|
|
|
Yes, it is third party libraries. And some API's from other groups in the company.... using Java. For our internal web APIs we do indeed share the data classes
There are code generators, but they require the web API to be augmented by for example Swagger... and last time I found one of these, Swagger certainly wasn't mature enough to generate anything that would actually work. That might have changed, but it would still require the API to expose Swagger metadata.
|
|
|
|
|
Oh, I would have loved to read the article about this. Sounds very interesting.
|
|
|
|
|
Mmmm... Can't find this article again... Oops.. :'(
A very short and summarized version of it.
You single WCF interface in pseudo code which fudge generic usage
interface IRemote
{
void Execute(Command cmd)
}
interface ICommandHandler<T> where T: Command
{
void Handle(T command);
}
class Service : IRemote
{
public void Execute(Command cmd)
{
IoC.GetCommandHandler(cmd.GetType()).Handle(cmd);
}
}
Additionally you have to write some code that enable to handle data contract (de)serialization of subclass transparently... be inspired by that class
class DataContractSerializerSettings
{
public DataContractResolver DataContractResolver { get; set; }
}
|
|
|
|
|
... Disguised been as a crow what doth upstart.
Actually, Upstart Crow is funnier. Made my day.
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|
I missed the first few episodes so now I have to wait for it to be repeated on Dave, five years from now. I wonder if it will still be funny?
|
|
|
|
|
It's on iPlayer[^], but episode 1 has already expired. Episode 2 expires tomorrow at 10:30 PM.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Yes, I knew I missed it. But it won't be the same unless I can see them all in the right order.
|
|
|
|
|
It's just been picked up for a second series and a Christmas special which suggests that it was possibly successful enough to merit a repeat on t'Beeb erelong, mayhap even a run on BBC1.
I am not a number. I am a ... no, wait!
|
|
|
|
|
It's been on TV, and you're in the UK, so you're legally entitled to watch (and keep) a recorded copy (but not a DVD rip).
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|
I needed to do deployment overnight but VPN gave up on me so I decided to be in the office early and do work before business starts work. Made myself a coffee and put it in takeaway cup to drink on the way.Left the house early and try to drink while at signal only to spill all the coffee on my trouser and car seat. Only thing left on my hand was lead and coffee cup decided to dance all over me. Had to drive back home to get changed. So much for waking up early to do the work. Just stepped into office to get a call system is not changed. Fixed it in few minutes and now they are happy. Now I am going to make me a coffee.
Zen and the art of software maintenance : rm -rf *
Maths is like love : a simple idea but it can get complicated.
|
|
|
|