To host WCF Service, we can just create an application, then point it to the project’s folder.
How the project looks in a browser:
Whenever the service being called, .NET runtime will first check if there’s a change to the source code. If it is changed, the runtime will then compile the website. I found this out by monitoring Temporary ASP.NET Files (which is configurable from web.config):
D:\projects\wcf\WCFService1\WCFService1Client\bin\Debug> WCFService1Client.exe
Enter number: 123
You entered: 123
Enter number: 12355
You entered: 12355
Enter number:
To use external library, we can need to create a bin folder, then drop the .dll into it. In this experiment, I use the dll generated from Robert Greiner’s NumberText.
I also modified Service.cs to utilize the new library:
// .. SNIP ...
using NumberText;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service" in code, svc and config file together.
public class Service : IService
{
public string GetData(int value)
{
return string.Format("You entered: {0} ( {1} ).", value, value.ToText());
}
// .. SNIP ...
}
The result is shown in the client:
D:\projects\wcf\WCFService1\WCFService1Client\bin\Debug> WCFService1Client.exe
Enter number: 19823
You entered: 19823 ( nineteen thousand eight hundred twenty three ).
Enter number: 1982
You entered: 1982 ( one thousand nine hundred eighty two ).
Enter number: 123
You entered: 123 ( one hundred twenty three ).
Enter number: 11
You entered: 11 ( eleven ).
The updated structure of Temporary ASP.NET Files (D:\projects\wcf\WCFService1\WCFService1_Temp):
That’s it for today. Next, I will look into WCF Service Application. Cheers!
About Hardono
Howdy! I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.
Windows Communication Foundation (WCF) service exposes contracts to its clients. Contract here refers to the platform-neutral and standard way of describing what is available/can be done in the service. Below are the types of contracts:
1. Service contracts
It describes what operations the client can call/perform on the service.
[ServiceContract]
interface ILibrary
{
[OperationContract]
bool Borrow(Book arg1, User arg2);
[OperationContract]
bool Return(Book arg1, User arg2);
}
2. Data contracts
It defines the data-type which will be passed, to and from the service. Built in types (int, string) will be implicitly defined. But complex/custom data type must be explicitly defined. The custom/complex data type must be serializable.
[DataContract]
struct Book
{
[DataMember]
public int Id;
[DataMember]
public string Title;
[DataMember]
public string ISBN;
}
3. Fault contracts
It defines what errors will be raised by the service, how it handles and propagates the error to its clients. Fault contract can only be declared on operation contract which returns value.
[ServiceContract]
interface ILibrary
{
[OperationContract]
[FaultContract(typeof(InvalidArgumentException))]
bool Borrow(Book arg1, User arg2);
[OperationContract]
[FaultContract(typeof(InvalidArgumentException))]
bool Return(Book arg1, User arg2);
}
4. Message contracts
A message is the packaged information which is sent to/from service. The package’s outer layer is the envelope. Inside the envelope, there is a header, and a body (similar to data defined by data contracts). A message contract allows the service to interact directly with messages (e.g. accessing information defined in the header)
[MessageContract]
public class BankingTransaction
{
[MessageHeader] public Operation operation;
[MessageHeader] public DateTime transactionDate;
[MessageBodyMember] private Account sourceAccount;
[MessageBodyMember] private Account targetAccount;
[MessageBodyMember] public int amount;
}
Howdy! I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.
One of the reason of my interest with Unity Framework is that its scripting is done in C#. The other reason is the ability to export the game to WebGL. This way we can create a game, and serve it through browser.
I have exported the incomplete game I created in my last post. Here’s the output folder:
Most of the files are the usual web resources: HTML, CSS, images and javascript. Except the content of build folder:
Since I’m not sure what are these .br files for, I take a peek using Notepad++:
Based on above, these .br files are brotli-compressed resources. Thankfully, I have enabled brotli compression on this blog. So I would expect that this blog should be able to serve the game without trouble. After uploading all the files and folders to https://sodeve.net/unity/index.html, I tested it in Firefox.
The game loading screen loads, but stuck at 90%:
This is where my nightmare starts as I encountered errors after errors.
Uncaught ReferenceError: unityFramework is not defined
Apparently the browser was unable to load build.framework.js.br. Looking at Network tab of Developer Tools:
NGINX is returning the incorrect Content-Type. It should application/x-javascript. From the response header, I can’t find Content-Encoding: br.
To fix this, we need to ensure NGINX return the correct content-type and content-encoding:
Uncaught (in promise) RangeError: too many arguments provided for a function call
Because it’s difficult to see the source of exception, I switched to Chrome because it has the ability to format the source code. Thanks to Chrome, I can identify where the exception was thrown (build.loader.js):
function(e) {
var t = new DataView(e.buffer,e.byteOffset,e.byteLength)
, r = 0
, n = "UnityWebData1.0\0";
if (!String.fromCharCode.apply(null, e.subarray(r, r + n.length)) == n)
throw "unknown data format";
r += n.length;
var o = t.getUint32(r, !0);
for (r += 4; r < o; ) {
var a = t.getUint32(r, !0);
r += 4;
var s = t.getUint32(r, !0);
r += 4;
var i = t.getUint32(r, !0);
r += 4;
var d = String.fromCharCode.apply(null, e.subarray(r, r + i)); //Exception source
r += i;
for (var u = 0, c = d.indexOf("/", u) + 1; c > 0; u = c,
c = d.indexOf("/", u) + 1)
l.FS_createPath(d.substring(0, u), d.substring(u, c - 1), !0, !0);
l.FS_createDataFile(d, null, e.subarray(a, a + s), !0, !0, !0)
}
l.removeRunDependency("dataUrl")
}
To help me debug, I format build.loader.js and made small change, put a breakpoint:
It seems we are trying to pass 795818 parameters to a function. No wonder we have “too many arguments provided for a function call” error. Since the offending line is simply converting array of uint to string, let’s rewrite it:
var zzz = e.subarray(r, r + i);
var d = ""; //String.fromCharCode.apply(null, zzz);
var ctr = 0,
len = zzz.length;
while (ctr < len) {
d += String.fromCharCode(zzz[ctr++]);
}
r += i;
Too bad, above code is very slow. Iterating 795818 items is painfully slow. Let's try to pass the maximum number parameters. Based on the documentation, we can pass at most 65535 (0xFFFF).
num1, ..., numN
A sequence of numbers that are UTF-16 code units. The range is between 0 and 65535 (0xFFFF). Numbers greater than 0xFFFF are truncated. No validity checks are performed.
With this information, let's modify the code:
var zzz = e.subarray(r, r + i);
var d = ""; //String.fromCharCode.apply(null, zzz);
var ctr = 0,
maxParamCount = 64000,
len = zzz.length;
while (ctr < len) {
var paramCount = ctr + maxParamCount >= len ? len - ctr : maxParamCount;
d += String.fromCharCode.apply(null, zzz.subarray(r + ctr, paramCount));
ctr += paramCount;
}
r += i;
It's a progress! A new error message discovered.
Uncaught (in promise) RangeError: offset is outside the bounds of the DataView
Last breakpoint before exception:
The cause is very obvious, let's add the fix:
for (r += 4; r < o && r < t.byteLength;) {
// ... SNIP ...
}
After deploying the change above, I no longer see the previous error. But now Unity throws many exceptions which I'm not sure how to handle.
[libil2cpp] ERROR: Could not open Il2CppData/Metadata/global-metadata.dat
No GlobalGameManagers file was found at , quitting player!
Failed to initialize player
I'll stop here for now. I'll ask around in Unity support forum, hopefully I can get my answer. Cheers!
UPDATE:
After asking around, most people said the issue is due to incorrect content-type / content-encoding. But as seen below, all .br have the correct content-type and content-encoding.
Oops.. .data.br doesn't have the correct content-encoding!!! Let's fix that by adding these lines to NGINX's configuration:
I also need to return build.loader.js into its original state. After making sure all responses are with correct content-encoding, the game loads!
About Hardono
Howdy! I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.