Happy #fsharp day! It's the 11th anniversary of F# being mass released in Visual Studio. A lot has changed since then, but thanks to excellent language stewardship code written in 2010 is still completely readable πhttps://t.co/54W806fvEQhttps://t.co/zDZntdX7f5
I've made some improvements to fsdocs/FSharp.Formatting to allow content (markdown in .md and .fsx) to contain cross-references to API docs. Available in 11.0.2https://t.co/7BtbVSAMSL
We've just released new version (5.5.0) of #fsharp@code plugin!
It includes some magic – better performance for the projects using signature files, big refactor and improvements in the signature help (including signature help for functions), fixes for units of measures and more
Thanks to @github it is now possible for sponsors to contribute via one-time payments so I've added a "buy me a coffee" option in case you wanted to sponsor but found a monthly payment a bit too much (which I totally understand)π#dotnet#fsharp#osshttps://t.co/3Jpg7kUBJD
Build new tech skills during #FreeApril! Weβre unlocking our entire Skills platform for free all month long. – 7,000+ expert-led video courses – 40+ interactive courses – 20+ projects – And more
π₯Updates to Docker support π₯Scaffolding for https://t.co/fWa8yTH1mB Core projects π₯Massive update to C# patterns and records support π₯Attach to a process from the Welcome screen
I am excited to announce my new project “OpenXML Package Explorer” extension for Visual Studio Code.
It allows to explore content of Office Open XML packages (*.pptx, *.docx, *.xlsx) inside Visual Studio Code. You can open any valid OpenXML package in Tree View, explore parts inside package, their relationships and content of xml parts (pre-formatted xml with highlighting).
I believe that source code of this extension can be used as one more sample of Fable-powered VSCode extension. Here is how it currently works:
F# source code compiled to JS using Fable 3 and bundled with webpack.
Code that interacts with OpenXML packages is written in .NET and uses the latest version of System.IO.Packaging
When extension is activated it starts .NET 5 process with API exposed using Fable.Remoting.
Extension assumes that .NET 5 runtime is installed on user machine but it depends on .NET Install Tool for Extension Authors that should help to install runtime to users that do not have it yet.
Fable.Remoting.Client cannot be used, because it is built on top of XMLHttpRequest that does not exist in Node.js world. Here is feature request for Fable.Remoting.NodeClient that may become a thing one day.
Current client-server communication is built on top of axios library and Fable.Axios bindings with manually written client.
Microsoft.Identity.Web is new (GA from Sept 30, 2020) library which contains a set of reusable classes used in conjunction with ASP.NET Core for integrating with the Microsoft identity platform (formerly Azure AD v2.0 endpoint) and AAD B2C.
The reason is not obvious from the error message. In fact, you browser calls the server with .AspNetCore.Cookies cookies that server cannot accept and cannot renew. What to do? Easy – open dev tool, clean cookies, refresh the page, wait for next server restart and repeat it again. You won’t last long.
The last line (AddInMemoryTokenCaches) configure application to use in-memory cache that is empty after each server restart. We need to find a way to store tokens outside the app process and restore the cache after process restart.
The only alternative to AddInMemoryTokenCaches is AddDistributedTokenCaches with ability to store tokens in memory, Redis, CosmosDB, SqlServer. Last three are nice options to distributed application but all of them are complicated for localhost development.
For our use case would be enough to serialise token cache to local file between restart. Luckily, it is not that complicated. We can implement IDistributedCache interface using TestDistributedCache as reference implementation.
public class LocalFileTokenCache : IDistributedCache
{
private class FileTransaction : IDisposable
{
public FileTransaction(string fileName = "cache.json")
{
var root = Path.GetDirectoryName(GetType().Assembly.Location);
_fileName = Path.Combine(root, fileName);
if (File.Exists(_fileName))
{
var str = File.ReadAllText(_fileName);
Dict = JsonSerializer.Deserialize<Dictionary<string, byte[]>>(str);
}
Dict ??= new Dictionary<string, byte[]>();
}
private readonly string _fileName;
public Dictionary<string, byte[]> Dict { get; }
public void Dispose()
{
var str =JsonSerializer.Serialize(Dict);
File.WriteAllText(_fileName, str);
}
}
public byte[] Get(string key)
{
using var cache = new FileTransaction();
return cache.Dict.TryGetValue(key, out var value) ? cache.Dict[key] : null;
}
public Task<byte[]> GetAsync(string key, CancellationToken token = default)
{
return Task.FromResult(Get(key));
}
public void Refresh(string key)
{
// Don't process anything
}
public Task RefreshAsync(string key, CancellationToken token = default)
{
Refresh(key);
return Task.CompletedTask;
}
public void Remove(string key)
{
using var cache = new FileTransaction();
cache.Dict.Remove(key, out _);
}
public Task RemoveAsync(string key, CancellationToken token = default)
{
Remove(key);
return Task.CompletedTask;
}
public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
{
using var cache = new FileTransaction();
cache.Dict[key] = value;
}
public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default)
{
Set(key, value, options);
return Task.CompletedTask;
}
}
LocalFileTokenCache implementation is not suitable for anything rather than local development.
The last step is to register LocalFileTokenCache in DI container as implementation of IDistributedCache instead of MemoryDistributedCache for development environment.
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
CurrentEnvironment = env;
}
public IConfiguration Configuration { get; }
private IWebHostEnvironment CurrentEnvironment{ get; set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(new[]
{
"User.Read", "Files.ReadWrite.AppFolder", "Files.ReadWrite"
}).AddDistributedTokenCaches();
if (CurrentEnvironment.IsDevelopment())
{
services.AddSingleton<IDistributedCache, LocalFileTokenCache>();
}
else
{
services.AddSingleton<IDistributedCache, MemoryDistributedCache>();
}
//...
}
//...
}
I'm finally done documenting our F# SQL libraries, nothing outstanding, but it might come in handy if you're dealing with SQLite, SQL Server or PostgreSQL.#fsharp#DotNet π
Lots of typos and grammar mistakes, but I can't be bothered to correct them now π
F# developers, if you are passionate about #fsharp web dev, then please help the #aspnetcore and F# team to design the APIs which you'll enjoy to use in the future:https://t.co/lZOkQsyZ3F
Zaid-Ajaj/Snowflaqe: A dotnet CLI to generate type-safe GraphQL clients for F# and Fable with automatic deserialization, static query verification and type checking
Hey #fsharp, @IonideProject released 5.4.1. This includes a lot of performance improvements. Also if you notice long initial loading times for your bigger projects, enable FSharp.enableMSBuildProjectGraph as this should help speed it up.https://t.co/ustHU4lHQj
So I did a small experiment to bring what I know from web dev in #fsharp and @FableCompiler to the desktop. Since everybody hates on Electron, I went and used @TryPhotino which hosts a lightweight chromium so I embedded a Suave + Feliz app in it https://t.co/HTtDVkj2jR
BooksBaum is doing an awesome job to improve ts2fable, the converter of Typescript declarations into #fsharp! Use it as a cli tool (check Readme) or directly from the website https://t.co/kqMDcCPgh5pic.twitter.com/Yt5jl2MM52
F# and F# tools update for Visual Studio 16.9! #fsharp
πββοΈ FSI from VS can be run on .NET Core now π New productivity features ποΈ Perf and responsiveness improvements π Core compiler improvements
Lots and lots of bug fixes, doc fixes, etc. .NET Standard 2.0 only. Please give it a spin and let me know if I messed something up by publishing it π
— Phillip Carter – F# and left-wing politics (@_cartermp) March 3, 2021