.NET Standard F# library does not store non-English characters properly - c#

I create a .NET Standard F# library with F# 4.3.4 (I also tested with 4.5) with the following code:
namespace ClassLibrary2
module Say =
let a = "国".Length.ToString()
let b = sprintf "%A" ("国".ToCharArray() |> Array.map int)
let c = "国"
When referencing that library from another project (.net core or .net framework):
Console.WriteLine(Say.a); // F# .net standard
Console.WriteLine(Say.b);
Console.WriteLine(Say.c == "国");
I get the following output:
2
[|65533; 65533|]
False
The equivalent C# .NET Standard library:
using System;
using System.Linq;
namespace ClassLibrary1
{
public static class Class1
{
public static string a = "国".Length.ToString();
public static string b = String.Join(", ", "国".ToCharArray().Select(i => ((int)i).ToString()));
public static string c = "国";
}
}
gives the expected output:
1
22269
True
Here's a repo showing the issue: https://github.com/liboz/Kanji-Bug.
This looks likely to be a bug, but I was wondering what would be a reasonable workaround for this problem? Specifically, I want to be able to be able to check equality for strings with something like Say.c = "国" where I might be using non-English characters while using a .NET Standard library.

So, the issue appears to be that the first file that the dotnet cli generates in an F# library does not use Unicode for its encoding. So, when creating a .NET Standard F# library that file for me was generated with Shift-JIS encoding, likely due to region settings on my own computer. Therefore, the solution to my issue was to simply save the default Library1.fs file with UTF-8 encoding manually so that it would have the same encoding as all the other files.

Related

How to simulate the printing of object like in C# Interactive Console?

An example:
If we type scoreDir in the C# Console, its content is pretty printed, i.e. the definition of the object, its length and its data.
I would like to simulate this printing with a built-in .NET method, e.g. ToString(). However, ToString() doesn't work, as showed. "Simulate" means I can generate the same printed string, but store it in a variable. Microsoft must have used some function to print such object; it's best to just re-use the function (no re-inventing the wheels).
Credits to #Hans Passant in the comment section.
In Visual Studio, after installing the Nuget package Microsoft.CodeAnalysis.CSharp.Scripting, the static function Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.CSharpObjectFormatter.Instance.FormatObject() can be used to mimic the same output as C# Interactive Console.
Here is the code that works:
using System;
using System.IO;
using System.Collections.Concurrent;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var scoreDir = new ConcurrentDictionary<(int, int), (double, int)>();
scoreDir.TryAdd((1, 2), (0.9, 3));
var res = Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.CSharpObjectFormatter.Instance.FormatObject(scoreDir);
Console.WriteLine(res);
}
}
}
Result:
There is no such build tool for this but you can convert it to Json. The problem with your example that is not so easy for a ConcurrentDictionary.
IMPORTANT NOTE:
This only will work for Newtonsoft and .NET 6.0 since System.Text.Json does not provide a cast for serialize to JSON ConcurrentDictionary and this also don't work for Newtonsoft in .NET Framework
How to Serialize to JSON string a ConcurrentDictionary?
Import Newtonsoft.Json from Nugget
Add using Newtonsoft.Json; to the references in the head of the file
ConcurrentDictionary<(int,int), (double,int)> scoreDir = new ConcurrentDictionary<(int,int), (double,int)>();
scoreDir.TryAdd((1,2),(0.9,3));
string jsonString = JsonConvert.SerializeObject(scoreDir);
Console.WriteLine(jsonString);
Returns:
{"(1, 2)":{"Item1":0.9,"Item2":3}}
Fiddle: https://dotnetfiddle.net/XzHHoN

Powershell vs C# EscapeUriString different results

I have the following problem when using standard C# code and command:
Uri.EscapeUriString("[]")
I get :
"[]"
but when I'm using PowerShell:
[Uri]::EscapeUriString("[]")
I get
"%5B%5D"
Could someone please explain me what the differences are in those method calls?
And why am I getting different results? How to force PowerShell to return the same results as standard c#?
Thanks in advance
This seems to be .NET version related. Your C# code probably uses a more recent version.
C#
// .NET 4.0
Uri.EscapeUriString("[]"); // OUTPUT: "%5B%5D"
// .NET 4.5
Uri.EscapeUriString("[]"); // OUTPUT: "[]"
PowerShell
# v5
[Uri]::EscapeUriString("[]") # OUTPUT: "%5B%5D"
# for reference
Add-Type "
using System;
namespace PowerShell
{
public static class Uri
{
public static string EscapeUriString(string stringToEscape)
{
return System.Uri.EscapeUriString(stringToEscape);
}
}
}"
[PowerShell.Uri]::EscapeUriString("[]") # OUTPUT: "%5B%5D"
There is no "Standard C#". The solution would be to make sure both are using the same .NET version, or implement your own escape method.
Alternatively, use System.Net.WebUtility.UrlEncode which seems to return "%5B%5D" in both cases.

Get value of version out of project.json

In a DNX application, which uses a "project.json" file, is there a way to read the value of the "version" property out of the "project.json" file?
I'm writing a library that writes something to the current HTTP response and I would like to show the version of the application in there.
Any help on how this can be done is highly appreciated.
If you set the version attribute during build (or in any other way) you can do this like that:
using System;
using System.Reflection;
[assembly:AssemblyVersionAttribute("1.2.3")]
namespace Test
{
class Program
{
public static void Main()
{
var assembly = typeof(Program).GetTypeInfo().Assembly;
var name = assembly.GetName();
Console.WriteLine($"{name.Name}: {name.Version}");
}
}
}
I did it using the new dotnet cli which is replacing dnx but it should work with dnx dnxcore50 as well.
Are you writing a Class Library or an ASP.NET application?
If a class Library, you could copy the version string to a resource file that you read in during run-time to grab the version. It's kind hard to do this sort of thing with class libraries since you don't get the beauty of a Startup and IoC.
If ASP.NET, then just add a version into your appsettings.json configuration (or a custom json file to store settings) and read it in at startup: http://docs.asp.net/en/latest/fundamentals/configuration.html
Multipe ways of doing this if you are running in a the web application, not a class library.
First way custom attributes data (should check if attribute is available):
this.GetType().Assembly.GetCustomAttributesData()
.First(x => x.AttributeType.FullName == "System.Reflection.AssemblyInformationalVersionAttribute")
.ConstructorArguments[0];
Second way
var name = this.GetType().AssemblyQualifiedName;
name = name.Substring(name.IndexOf("Version=") + 8);
var verion = name.Substring(0, name.IndexOf(", "));

Namespace problems in QuickFix's .Net DLL wrapper

I'm battling with the QuickFix engine in .Net (using the C++ DLL wrapper) to craft a TradeCaptureReportRequest message:
var req = new QuickFix44.TradeCaptureReportRequest();
req.set(new QuickFix.SubscriptionRequestType(QuickFix.SubscriptionRequestType.SNAPSHOT_PLUS_UPDATES)); // 263
req.set(new QuickFix.TradeRequestID("testing" + DateTime.Now.Second.ToString())); // 568
var nodates = new QuickFix44.TradeCaptureReportRequest.NoDates();
nodates.set(new QuickFix.TradeDate("20130201"));
req.set(nodates); // 580
Everything seems to look good until I call req.set(nodates), which causes a compiler error saying that "NoDates cannot be converted to a NoDates".
This boggles my mind since when I navigate to the metadata of the TradeCaptureRequest within the QuickFix dll, i am shown this.
public void set(NoDates value);
// as a member of QuickFix44.TradeCaptureReportRequest
if I go to the definition of NoDates it sends me to the QuickFix44.TradeCaptureReportRequest.NoDates Class defined within the QuickFix44.TradeCaptureReportRequest class.
however there is a NoDates Class defined within the QuickFix namesapace which compiles just fine when I do the following.
req.set(new QuickFix.NoDates(1));
I'm using Quickfix v4.0.30128 and the .Net wrapper for the C++ DLL.
If you look at the C# code for TradeCaptureReportRequest.set you'll find that it would like a QuickFix.NoDates type for the NoDates value:
// line: 1993
public void set(QuickFix.NoDates value)
{ setField(value); }
So change your C# to the following:
var nodates = new QuickFix.NoDates();
nodates.set(new QuickFix.TradeDate("20130201"));
req.set(nodates);
It appears you're using the QuickFix .Net wrapper over the C++, which is an abomination of .Net programming guidelines. I highly recommend you switch to QuickFIX/N, which is less horrible (but still awful looking).

F# declared namespace is not available in the c# project or visible through the object browser

F# declared namespace is not available in the c# project or visible through the object browser.
I have built a normal F# library project, but even after i build the project and reference it to my C# project, I am unable to access the desired namespace.
I am also unable to see it in the object browser, i get an error telling me that it has not been built. I am running on the september release can someone point out my error ?
F# Version 1.9.6.0
(6) Edit : Referencing the dll directly has fixed my problem, referencing the project allows me to compile but the intellisence does not work. When the dll is directly referenced the intellisence works perfectly.
This is the code found in the .fs file
#light
namespace Soilsiu.Core
module public Process =
open System.Xml.Linq
let private xname (tag:string) = XName.Get(tag)
let private tagUrl (tag:XElement) = let attribute = tag.Attribute(xname "href")
attribute.Value
let Bookmarks(xmlFile:string) =
let xml = XDocument.Load(xmlFile)
xml.Elements <| xname "A" |> Seq.map(tagUrl)
let PrintBookmarks (xmlFile:string) =
let list = Bookmarks(xmlFile)
list |> Seq.iter(fun u -> printfn "%s" u)
(5) Edit : Could ReSharper 4.0 be the problem?
(4) Edit : When i say the Object browser is unable to read the resulting assembly, i mean that when I try to open the assembly in the object browser i get an error telling me the project has not yet been built. yet again i can read the assembly using reflector.
(3) Edit : Reflector can Disassemble the dll but the Object Browser is unable to read it.
(2) Edit : I have Upgraded my F# version to 1.9.6.2 and still the same consequence
(1) Edit : I was able to Disassemble the dll to C# I get : (Everything seems to be fine here)
namespace Soilsiu.Core
{
[CompilationMapping(7)]
public static class Crawler
[CompilationMapping(7)]
public static class Process
}
[CompilationMapping(7)]
public static class Process
{
// Methods
static Process();
public static IEnumerable<string> Bookmarks(string xmlFile);
public static void PrintBookmarks(string xmlFile);
internal static string tagUrl(XElement tag);
internal static XName xname(string tag);
// Nested Types
[Serializable]
internal class clo#13 : FastFunc<XElement, string>
{
// Methods
public clo#13();
public override string Invoke(XElement tag#9);
}
[Serializable]
internal class clo#17 : FastFunc<string, Unit>
{
// Methods
public clo#17();
public override Unit Invoke(string u);
}
}
What if you reference the produced DLL directly (i.e., not via a project reference, but via a file reference)?
Maybe IntelliSense is just messed up? What compiler error do you get when you try to use it in C#? When you say "the object browser is unable to read it" what does that mean?
For what it's worth, I added this to a F# library project, referenced it (project) from a C# console app, and was able to use it. IntelliSense did not work at first though. (Had to rebuild.)
If you can make a solid repro, I'd suggest emailing it to F# bugs alias (fsbugs).
I tried the same thing. It looks as if Visual Studio and Resharper 4.0 doesn't understand F# for some reason. If you ignore the sea of red text and the lack of intellisense, it will compile fine.
Try
Make sure that C# project is targeted FULL .NET (NOT Client Profile).
Add references to assemblies into C# project which are used by F# project.

Categories

Resources