F

注意: .NETC#も含む

ガイド

.NET

GitHub

Description Link
C# language design https://github.com/dotnet/csharplang
Compiler implementation https://github.com/dotnet/roslyn
Standard to describe the language https://github.com/dotnet/csharpstandard

コマンド

バージョン
dotnet --version

Emacs連携

FSAutoCompleteが導入できないとき

コマンドが誤っています

dotnet-path/to/.emacs.d/.cache/lsp/fsautocomplete/fsautocomplete.dllが見つかりません.

FsAutoComplete

fsi

Macでの調整

EmacsでのFSACエラー

cat /etc/dotnet/install_location

/usr/local/share/dotnet/x64
->
/usr/local/share/dotnet

trydotnet, ifsharp, Jupyter notebook with .NET Core

Try .NET, Jupyter notebook with .NET Core

要調査: これ用にインストールしたパッケージは ~/.trydotnet に置かれる?

dotnet tool install --global Microsoft.dotnet-interactive
dotnet interactive jupyter install
jupyter kernelspec list

IFsharp へのパッケージ導入

trydotnet でも同じ?

まとめ
#load "Paket.fsx"
Paket.Package ["Newtonsoft.Json"; "Deedle"; "MathNet.Numerics"; "MathNet.Numerics.FSharp"; ]
#load "Paket.Generated.Refs.fsx"

open System
open Deedle
open MathNet.Numerics
open Newtonsoft.Json\
open MathNet.Numerics.LinearAlgebra

load "XPlot.Plotly.Paket.fsx"
load "XPlot.Plotly.fsx""
open FSharp.Core
open XPlot.Plotly

// 以下はF# 5以降の方法:いったんコメントアウト。
//#r "nuget:Deedle"
//#r "nuget:DiffSharp"
//#r "nuget:FSharpPlus"
//#r "nuget:MathNet.Numerics"
//#r "nuget:MathNet.Numerics.FSharp"
//#r "nuget:XPlot"
ツイートからのやりとり

緩募 IFsharp で DiffSharp を使う方法. そもそもどうやって導入すればいいのかさえわからない. Powershell で dotnet add package DiffSharp --version 0.7.7 と打ったら「プロジェクトが見つかりませんでした」とか言われて怒られる. Install-Package でもうまくいかない. つらい.

そもそも .NET には一般のプログラミング言語と違いグローバルなライブラリ環境が存在しない, ということに注意が必要です. では dotnet add package や Install-Package は何をするコマンドなのかというと, 単一のプロジェクト (*.fsproj) に依存パッケージを追加するコマンドです.

一方 IFSharp は F# interactive の上に構築されているのでプロジェクトが存在しません. ではどうすればよいのかというと, ここに記載されているように

load "Paket.fsx"

としてから Paket.Package もしくは Paket.Version (バージョン指定) に使いたいパッケージ名を渡し,

load "Paket.Generated.Refs.fsx"

とすることでパッケージを IFSharp の環境にインストールすることができます. 初回実行時にはパッケージの依存解決とダウンロードが走るので処理に時間がかかります. また Paket を使うセルは他の処理と分けておいた方がよいです (補完を利かせるため).

vscode連携

ツールチップなどが出てこない

やたらエラーが出る

Windowsでの英語化

アップデート

アンインストール

Mac

/tmp直下

事前にバージョン(curlでのダウンロード先)を確認すること.

cd /tmp
curl -OL https://github.com/dotnet/cli-lab/releases/download/1.5.255402/dotnet-core-uninstall.tar.gz
mkdir -p /tmp/dotnet-core-uninstall
tar -zxf dotnet-core-uninstall.tar.gz -C dotnet-core-uninstall
cd dotnet-core-uninstall
dotnet-core-uninstall list
./dotnet-core-uninstall -h
~/tmp直下

事前にバージョン(curlでのダウンロード先)を確認すること.

cd ~/tmp
curl -OL https://github.com/dotnet/cli-lab/releases/download/1.5.255402/dotnet-core-uninstall.tar.gz
mkdir -p ~/tmp/dotnet-core-uninstall
tar -zxf dotnet-core-uninstall.tar.gz -C dotnet-core-uninstall
cd dotnet-core-uninstall
dotnet-core-uninstall list
./dotnet-core-uninstall -h

インストール

Windows

M1 Mac

Linux

dotnet-install.shを使うとき

プロジェクト作成

VSCodeを前提にする.

setup.txt

dotnet new sln -o MySolution
cd MySolution
mkdir src
dotnet new console -lang F# -o src/MyProject
dotnet sln add src/MyProject/MyProject.fsproj
mkdir tests
dotnet new xunit -lang F# -o tests/MyProjectTests
dotnet sln add tests/MyProjectTests/MyProjectTests.fsproj
cd tests/MyProjectTests
dotnet add reference ../../src/MyProject/MyProject.fsproj
dotnet add package FsUnit
dotnet add package FsUnit.XUnit
dotnet build
dotnet test

記事集

公式情報

よくまとまっていて参考になる

MISC

読書メモ, 2022 MASTERING MINIMAL APIS IN ASPNET CORE

1章

dotnet --list-sdk

2章

dotnet tool install -g LiveReloadServer
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

3章

ASP.NETかつM1 Macでのキーチェーン要求を解除する

ASP.NET 開発中にhttpsを使う

dotnet dev-certs https --clean
dotnet dev-certs https --trust

ASP.NET 初期化

dotnet restore
dotnet tool restore

ASP.NET 導入メモ: global.json

{
  "sdk": {
    "version": "6.0.400"
  }
}

ASP.NET 導入メモ: docker-compose.yml

PORT=3000

DB_ROOT_HOST="%"
DB_ROOT_USER=postgres
DB_ROOT_PASS=root
POSTGRES_USER=user
DB_USER=user
DB_PASS=pass
DB_PORT=5432
DB_NAME=mydb
TZ=Asia/Tokyo
version: "3"
services:
  pgsql:
    image: postgres:14
    platform: linux/x86-64
    tty: true
    env_file: .env
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASS}
      POSTGRES_DB: ${DB_NAME}
      TZ: ${TZ}
    ports:
      - ${DB_PORT}:5432
    # volume:
    #   - ./db/init:/docker-entrypoint-initdb.d
    healthcheck:
      test: [ "CMD", "pg_isready", "-U", "${POSTGRES_USER}", "||", "exit", "1" ]
      interval: 2s
      timeout: 5s
      retries: 5

ASP.NET 導入メモ: docker-compose.with-dotnet.yml

PORT=3000

DB_ROOT_HOST="%"
DB_ROOT_USER=postgres
DB_ROOT_PASS=root
POSTGRES_USER=user
DB_USER=user
DB_PASS=pass
DB_PORT=5432
DB_NAME=mydb
TZ=Asia/Tokyo
version: "3"
services:
  pgsql:
    image: postgres:14
    platform: linux/x86-64
    tty: true
    env_file: .env
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASS}
      POSTGRES_DB: ${DB_NAME}
      TZ: ${TZ}
    ports:
      - ${DB_PORT}:5432
    healthcheck:
      test: [ "CMD", "pg_isready", "-U", "${POSTGRES_USER}", "||", "exit", "1" ]
      interval: 2s
      timeout: 5s
      retries: 5
  backend:
    image: "mcr.microsoft.com/dotnet/sdk:6.0"
    volumes:
      - ./Database:/app
    command: dotnet watch --project ./app run --urls "http://0.0.0.0:80"
    ports:
      - "80:80"

ASP.NET 導入メモ: ツールのインストール

dotnet new tool-manifest
dotnet tool install dotnet-ef --version 6.0.12
dotnet tool install Microsoft.Web.LibraryManager.Cli
dotnet tool uninstall --global dotnet-ef
dotnet tool install --global dotnet-ef --version 6.0.12

ASP.NET 導入メモ: パッケージのインストール

dotnet add package Microsoft.EntityFrameworkCore --version 6.0.12
dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 6.0.12
dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 6.0.12
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 6.0.8
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.EntityFrameworkCore.SqlServer -v 6.0.12 # scaffoldで必要
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design -v 6.0.11

ASP.NET 導入メモ: Program.csへの各データベース設定

SQLite

builder.Services.AddDbContext<MyDbContext>(options =>
    options.UseSqlite(builder.Configuration.GetConnectionString("MyDbContext") ??
                      throw new InvalidOperationException("Connection string 'MyDbContext' not found.")));

In Memory

builder.Services.AddDbContext<MyDbContext>(opt =>
    opt.UseInMemoryDatabase("mydb"));

PostgreSQL

builder.Services.AddDbContext<MyDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("MyDbContext") ??
                      throw new InvalidOperationException("Connection string 'MyDbContext' not found.")));

ASP.NET 導入メモ: フロントエンド用ライブラリ導入, LibManでのインストール

dotnet libman init -p cdnjs
dotnet libman install bootstrap --provider cdnjs --destination wwwroot/lib/bootstrap
dotnet libman install jquery --provider cdnjs --destination wwwroot/lib/jquery
dotnet libman install jquery-validate --provider cdnjs --destination wwwroot/lib/jquery-validation
dotnet libman install jquery-validation-unobtrusive  --provider cdnjs --destination wwwroot/lib/jquery-validation-unobtrusive
dotnet libman install @fluentui/web-components --provider cdnjs --destination wwwroot/lib/fluentui/web-components

ASP.NET 導入メモ: データベースのスキャフォールド

dotnet dotnet-ef dbcontext scaffold 'Host=localhost;Database=mydb;Username=user;Password=pass' Npgsql.EntityFrameworkCore.PostgreSQL --output-dir Models --context-dir Context --context MyDbContext

ASP.NET 導入メモ: コントローラーのスキャフォールド

dotnet tool install dotnet-aspnet-codegenerator --version 6.0.11
dotnet dotnet-aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers

ASP.NET 導入メモ: MVCとAPIの共存

// API利用:`Swashbuckle.AspNetCore`が必要
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "ToDo API",
        Description = "An ASP.NET Core Web API for managing ToDo items",
        TermsOfService = new Uri("https://phasetr.com/archive"),
        Contact = new OpenApiContact
        {
            Name = "Example Contact",
            Url = new Uri("https://phasetr.com/contact")
        },
        License = new OpenApiLicense
        {
            Name = "Example License",
            Url = new Uri("https://phasetr.com/archive")
        }
    });
});

// 中略: `var app = builder.Build();`のあと

// API利用:開発時は`Swagger`を立ち上げる
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

// API利用
app.MapControllers();
using Microsoft.AspNetCore.Mvc;
using HogeProject.Models;

namespace HogeProject.Controllers.Api.V1;

// 次のディレクティブの追加: これでAPI呼び出しでき, `Swagger`にも反映される
[ApiController]
[Route("api/v1/[controller]")]
public class HogeController : ControllerBase
{
    // 本体
}

ASP.NET 導入メモ: EF Coreのマイグレーション

ASP.NET Program.cs, WebApplicationBuilder

ASP.NET Program.cs, WebApplicationBuilderのプロパティ

ASP.NET Blazor: フロントに送る容量をおさえつつBlazorを使う

ASP.NET Razor Class Library (RCL)

builder.Services.AddRazorPages();
app.MapRazorPages();

ASP.NET Razor Pages @page

ASP.NET Razor Pages @page キャッチオールパラメータ

ASP.NET Razor Pages @page ルート制約

ASP.NET Razor Pages addTagHelperディレクティブ

ASP.NET Razor Pages HTMLエンコードしたくない場合

@{
    Layout = "_Layout";
    const string output = "<p>This is a paragraph.</p>";
}

<div>
    <p>@output</p>
    <p>@Html.Raw("<p>This is a paragraph.</p>")</p>
</div>

ASP.NET Razor Pages HTMLエンコードレベルを下げる, WebEncoderOptions

builder.Services.Configure<WebEncoderOptions>(options =>
{
   options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement);
});

ASP.NET Razor Pages removeTagHelperディレクティブ: 特定のタグの処理を選択的にオプトアウト

@removeTagHelper "Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers"
<!a href="https://www.learnrazorpages.com">Learn Razor Pages</!a>

@tagHelperPrefix x:
<x:a asp-page="/Index">Home</x:a>

ASP.NET Razor Pages _Layoutを探す場所

ASP.NET Razor Pages URLの処理, スラッグなど

ASP.NET Razor Pages ViewBag

ASP.NET Razor Pages ViewData

ViewData["Title"] = "Welcome!";

<title>@ViewData["Title"] - WebApplication1</title>

ASP.NET Razor Pages View Model

ASP.NET Razor Pages View Model ハンドラーメソッドのパラメーター

@{
    Layout = "_Layout";
}

<div>
    <p>@Model.Message</p>
</div>


public class Index : PageModel
{
    public string Message { get; set; } = string.Empty;
    public void OnGet(int id)
    {
        Message = $"OnGet executed with id = {id}";
    }
}

ASP.NET Razor Pages View Model 名前つきハンドラーメソッド

@page
@model WelcomeModel
@{
}

<div class="col">
    <form method="post" asp-page-handler="Search">
        <p>Search</p>
        <input name="searchTerm" />
        <button>Search</button>
    </form>

    <form method="post" asp-page-handler="Register">
        <p>Register</p>
        <input name="email" />
        <button>Register</button>
    </form>
    <p>@Model.Message</p>
</div>

public class WelcomeModel : PageModel
{
    public string Message { get; set; }
    public void OnPostSearch(string searchTerm)
    {
        Message = $"You searched for {searchTerm}";
    }

    public void OnPostRegister(string email)
    {
        Message = $"You registered {email} for newsletters";
    }
}

ASP.NET Razor Pages アクションの結果

ASP.NET Razor Pages カスタム検証属性

ASP.NET Razor Pages コメントの書き方

ASP.NET Razor Pages ビューコンポーネント

ASP.NET Razor Pages 標準コードブロックとfunctionsコードブロックの違い

ASP.NET Razor Pages 部分ビュー

ASP.NET Razor Pages ページごとにテンプレートの一部だけ書き換える

ASP.NET Razor Pages ページモデル [DataType]属性

ASP.NET Razor Pages モデルバインディング

    [BindProperty] public string CityName { get; set; } = string.Empty;
    [BindProperty(SupportsGet=true)] public int Id  { get; set; } = 0;
    [BindProperty(Name="e-mail")] public string Email { get; set; } = "";


<div class="col-4">
    <h3>モデルバインディング</h3>
    <form method="post">
        <div class="mb-3">
            <label for="name">Enter city name</label>
            <input class="form-control" type="text" name="cityName"/>
        </div>
        <button class="btn btn-primary">Submit</button>
    </form>
    @if (Request.HasFormContentType && !string.IsNullOrWhiteSpace(Model.CityName))
    {
        <p>You submitted @Model.CityName</p>
    }
</div>

ASP.NET Razor Pages リテラル文字列の表示

@foreach (var city in cities)
{
   if (city.Country == "UK")
   {
       @:Country:  @city.Country, Name: @city.Name
   }
}

@foreach (var city in cities)
{
   if (city.Country == "UK")
   {
       <text>Country:  @city.Country<br />
       Name: @city.Name</text>
   }
}

ASP.NET Razor Pages リモートバリデーション

ASP.NET Razor Pages ローカリゼーション

ASP.NET URL末尾に常にスラッシュをつける

ASP.NET タグヘルパー

ASP.NET タグヘルパー asp-for

<input asp-for="CityName" />

// => <input type="text" id="CityName" name="CityName" value="" />

ASP.NET タグヘルパー asp-format

ASP.NET タグヘルパー [Display(Name="Hoge Fuga")]

[BindProperty]
public string Name { get; set; }
[BindProperty]
[Display(Name = "Maximum Number Of Guests")]
public int MaxNumberOfGuests { get; set; }
[BindProperty]
[Display(Name ="Day Rate")]
public decimal DayRate { get; set; }
[BindProperty]
[Display(Name = "Smoking Permitted")]
public bool SmokingPermitted { get; set; }
[BindProperty]
[DataType(DataType.Date)]
[Display(Name ="Available From")]
public DateTime AvailableFrom { get; set; }

ASP.NET タグヘルパー select

using Microsoft.AspNetCore.Mvc .Rendering

public class CreateModel : PageModel
{
    [BindProperty]
    [Display(Name = "City")]
    public int SelectedCity { get; set; }
    public SelectList Cities { get; set; }
    public string Message { get; set; }
    public void OnGet()
    {
        Cities = GetCityOptions();
    }

    public void OnPost()
    {
        Cities = GetCityOptions();
        if (ModelState.IsValid)
        {
            var city = GetCityOptions().First(o => o.Value == SelectedCity.ToString());
            Message = $"You selected {city.Text} with value of {SelectedCity}";
        }
    }

    private SelectList GetCityOptions()
    {
        var cities =  new List<City>
        {
            new City{ Id = 1, Name = "London"},
            new City{ Id = 2, Name = "Paris" },
            new City{ Id = 3, Name = "New York" },
            new City{ Id = 4, Name = "Rome" },
            new City{ Id = 5, Name = "Dublin" }
        };
        return new SelectList(cities, nameof(City.Id), nameof(City.Name));
    }

    private SelectList GetCityOptions2()
    {
       var cities =  new List<SelectListItem>
       {
           new SelectListItem{ Value = "1", Text = "London"},
           new SelectListItem{ Value = "2", Text = "Paris" },
           new SelectListItem{ Value = "3", Text = "New York", Selected = true },
           new SelectListItem{ Value = "4", Text = "Rome" },
           new SelectListItem{ Value = "5", Text = "Dublin" }
       };
       return new SelectList(cities);
    }
}


@if (Request.HasFormContentType)
{
    <p>You selected @Model.SelectedCity</p>
    <p>@Model.Message</p>
}
<form method="post">
    <div class="mb-3">
        <label class="form-label" asp-for="SelectedCity"></label>
        <select class="form-control" asp-for="SelectedCity" asp-items="Model.Cities"></select>
    </div>
    <button class="btn btn-primary">Submit</button>
</form>

ASP.NET タグヘルパー select, optGroup

public string CountryName { get; set; }
private SelectList GetCityOptions()
{
   var cities = new List<City>
   {
       new City{ Id = 1, Name = "Barcelona" , CountryName = "Spain" },
       new City{ Id = 2, Name = "Cadiz" , CountryName = "Spain" },
       new City{ Id = 3, Name = "London", CountryName = "United Kingdom" },
       new City{ Id = 4, Name = "Madrid" , CountryName = "Spain" },
       new City{ Id = 5, Name = "Rome", CountryName = "Italy" },
       new City{ Id = 6, Name = "Venice", CountryName = "Italy" },
       new City{ Id = 7, Name = "York" , CountryName = "United Kingdom" },
   };
   return new SelectList(cities, nameof(City.Id), nameof(City.Name), null, nameof(City.CountryName));
}

ASP.NET タグヘルパー ファイルアップロード

ASP.NET タグヘルパー ファイルアップロード時の拡張子制限

ASP.NET リクエストへの容量制限

ASP.NET ルート制約の非同期処理

C# Delegate

delegate int MyDelegate(DateTime dt);
int GetMonth(DateTime dt)
{
    return dt.Month;
}
int PointlessAddition(DateTime dt)
{
    return dt.Year + dt.Month + dt.Day;
}

MyDelegate example1 = GetMonth;
MyDelegate example2 = PointlessAddition;
Console.WriteLine(example1(DateTime.Now));
Console.WriteLine(example2(DateTime.Now));
MyDelegate example3 = delegate(DateTime dt) { return dt.Now.AddYears(-100).Year; };
Console.WriteLine(example3(DateTime.Now));

MyDelegate example4 = (dt) => { return dt.Now.AddYears(-100).Year; };
Console.WriteLine(example4(DateTime.Now));

dotnet-user-secrets

dotnet コマンドサンプル

dotnet new globaljson --sdk-version 6.0.400 --output <projname>
dotnet new mvc --no-https --output <projname> --framework net6.0
dotnet new sln -o <projname>
dotnet sln PartyInvites add <projname>

dotnet --list-sdks
dotnet watch
dotnet run
dotnet list package
dotnet add package <hoge> --version
dotnet remove package <hoge>

dotnet tool uninstall --global dotnet-ef
dotnet tool install --global dotnet-ef --version 6.0.0
dotnet ef --help
dotnet ef database drop --force --context StoreDbContext

dotnet tool uninstall -g Microsoft.Web.LibraryManager.Cli
dotnet tool install -g Microsoft.Web.LibraryManager.Cli --version 2.1.113
libman init -p cdnjs
libman install bootstrap@5.1.3 -d wwwroot/lib/bootstrap

dotnet コマンドラインでSDKのバージョンを指定する

dotnet --list-sdks

dotnet ソリューション初期化

dotnet new sln # 現在のディレクトリに同名のファイル生成
dotnet new sln --name <MySolution> # 現在のディレクトリにファイル生成
dotnet new sln --output <MySolutionDirectory> # 指定したディレクトリに生成

dotnet ソリューションへのプロジェクト追加

dotnet sln add <HogeProject>

dotnet 使えるテンプレートのリスト

dotnet new --list

dotnet パッケージを削除する

dotnet remove package <hoge>

dotnet プロジェクト初期化時の参考

dotnet new globaljson --sdk-version <6.0.100> --output <MySolution/MyProject>
dotnet new web --no-https --output <MySolution/MyProject> --framework <net6.0>
dotnet new sln -o <MySolution>
dotnet sln <MySolution> add <MySolution/MyProject>

EF Core インストール

dotnet add package Microsoft.EntityFrameworkCore --version 6.0.12
dotnet add package Microsoft.EntityFrameworkCore.InMemory

dotnet tool uninstall --global dotnet-ef
dotnet tool install --global dotnet-ef --version 6.0.12

EF Core C#の型とデータベースの型を合わせる

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace SportsStore.Models;

public class Product
{
    public long? ProductId { get; set; }

    [Required(ErrorMessage = "Please enter a product name")]
    public string Name { get; set; } = string.Empty;

    [Required(ErrorMessage = "Please enter a description")]
    public string Description { get; set; } = string.Empty;

    [Required]
    [Range(0.01, double.MaxValue,
        ErrorMessage = "Please enter a positive price")]
    [Column(TypeName = "decimal(8, 2)")]
    public decimal Price { get; set; }

    [Required(ErrorMessage = "Please specify a category")]
    public string Category { get; set; } = string.Empty;
}

EF Core シードを使う

using SportsStore.Models;
SeedData.EnsurePopulated(app);

EF Core データベースのリセット

dotnet ef database drop --force --context <データベースコンテキスト>

EF Core 認証

EF Core 認証用ユーザーにリレーションを張る

using Microsoft.AspNetCore.Identity;

namespace <ProjectName>.Models;

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; } = string.Empty;

    public string LastName { get; set; } = string.Empty;

    public DateTime BirthDate { get; set; }

    public virtual IEnumerable<Article>? Articles { get; set; }
}


namespace <ProjectName>.Models;

public class Article
{
    public int ArticleId { get; set; }

    public string Title { get; set; } = string.Empty;

    public string Description { get; set; } = string.Empty;

    public string? UserId { get; set; }

    public virtual ApplicationUser? User { get; set; }
}

EF Core 認証用ユーザーの主キーを変える

EF Core マイグレーションの作成

dotnet dotnet-ef migrations add InitialCreate
dotnet dotnet-ef migrations add Rating
dotnet dotnet-ef migrations add InitialCreate -c <データベースコンテキスト>
dotnet ef migrations add InitialCreate

EF Core マイグレーションの反映

dotnet dotnet-ef database update

EF Core マイグレーションのundo

dotnet ef migrations remove

EF Core リレーションの設定

F# .envファイルを読み込みたい

open System
open System.IO

let parseLine(line : string) =
  Console.WriteLine (sprintf "Parsing: %s" line)
  match line.Split('=', StringSplitOptions.RemoveEmptyEntries) with
  | args when args.Length = 2 -> Environment.SetEnvironmentVariable(args.[0], args.[1])
  | _ -> ()

let load() =
  lazy (
    Console.WriteLine "Trying to load .env file..."
    let currentDir = Directory.GetCurrentDirectory()
    let pDir = Directory.GetParent(currentDir).ToString() // 都合によって親ディレクトリの.envを読んでいるが必要なければ削除
    let filePath = Path.Combine(pDir, ".env") // 親ディレクトリの.envを読んでいるので同じディレクトリにあるなら適切に書き換える
    filePath
    |> File.Exists
    |> function
      | false -> Console.WriteLine "No .env file found."
      | true  -> filePath |> File.ReadAllLines |> Seq.iter parseLine
  )
let init = load().Value

// 環境変数から読み込む部分
let apiRootUrl = Environment.GetEnvironmentVariable "NEXT_PUBLIC_API_ROOT_URL"

F# bottom

let undefined<'T> : 'T = failwith "Not implemented yet"

let stub1 (x : int) : float = undefined
let stub2 (x : 'T) : 'T = undefined
let undefined<'T> : 'T = raise (NotImplementedException())

F# fsx実行: 競プロ用実行

dotnet fsi hoge.fsx
dotnet fsi hoge.fsx < input.txt

F# fsxで他のfsxを読み込む

#load "Script1.fsx"
open Script1

F# Fable

メモ

dotnet new --install Fable.Template
dotnet new fable

F# Json

open System.Text.Json
open System.Text.Json.Serialization
open System.Text.Encodings.Web
open System.Text.Unicode

let mutable options = JsonSerializerOptions()
options.Encoder <- JavaScriptEncoder.Create(UnicodeRanges.All)
let jsonString = JsonSerializer.Serialize(items, options)
System.IO.File.WriteAllText(outputJsonFileName, jsonString, System.Text.Encoding.UTF8)

F# Stack overflow

AtCoderの木DPで, Pythonコードに沿って実装してみたらStack overflowしたのでその対処の記録.

F# Stringにはreverseがない(?)ので代替策を見つけた

どなたか有識者の方, いい感じのメソッドがあれば教えてほしい. 今回はProject Euler Problem 4の回文数の問題を解いているときに出くわした. どうもStringにはreverseメソッドがないらしい. 検索した結果, 今回はこのページのコピペとして次のコードを採用した.

let reverse (s : string) = s |> Seq.toArray |> Array.rev |> System.String
s |> Seq.rev |> System.String.Concat

あと最近F#のリファレンスがGitHubにうつったようだ. そのリンクも改めて貼っておこう.

GitHubのAlgorithmsAndDataStructureByFSharpにアルゴリズム系のコードと共にF#の「ライブラリ」という名の自分用コードサンプル集を作ってある. 具体的にはLibraryディレクトリがそう. そのうち競プロ用にいろいろ調べたことを改めてLibraryにまとめ直したい. 何はともあれ,

F#, とにかく情報がないので地道に貯めていく.

F# 型プロバイダー FSharp.Dataの型プロバイダーには定数しか渡せない

#r "nuget: FSharp.Data"
open FSharp.Data
open FSharp.Data.HttpRequestHeaders

let toJson = fun (x: HttpResponse) ->
  match x.Body with
  | Text t -> t
  | _ -> failwith "bytes"

/// http://localhost
type Root = FSharp.Data.JsonProvider<"http://localhost">
Http.Request("http://localhost", httpMethod = "GET") |> toJson |> fun t -> Root.Parse(t)

F# 型プロバイダー 実行時のディレクトリ指定

#r "nuget: FSharp.Data"
open FSharp.Data

type Comments = JsonProvider<"sampleResponse.json", ResolutionFolder=__SOURCE_DIRECTORY__>;;

F# 関数に型をつける

ふつうの方法

let f (i:int) (j:int): int = i * j

ラムダを使う方法

let f: int -> int -> int =
  fun i j -> i * j

F# 空シーケンスの判定, 特にmatch

let rec dropWhile p xs =
  match xs with
    | s when Seq.isEmpty s -> Seq.empty
    | _ -> if p (Seq.head) then dropWhile p (Seq.tail xs) else (Seq.tail xs)

F# 遅延リストはとりあえずSeq

Seq.initInfinite (fun i -> 2 * i + 1)

F# ファイルの読み書き

let fileName = "1.tmp.txt"
System.IO.File.WriteAllText(fileName, someString, System.Text.Encoding.Default)

F# 複数行の文字列, ヒアドキュメント

C#と同じように書ける模様. 特に三重引用符または「@+クオート」で書ける. ついでに逐次的リテラル文字列の概念があり, 後者の「@+クォート」形式がそれ. 例を引用しておく.

".¥¥hoge¥¥hoge¥¥hoge.txt" // ふつうの文字列
@".¥hoge¥hoge¥hoge.txt"   // 逐次的リテラル文字列