くうと徒然なるままに

ゆるふわ を志向している なごやかです。

Azure Function + Azure Table Storage で CRUD してみる

ハッカソンで必要な知識だったので試した記録

Azure Function とは

今、話題のサーバーレスとか呼ばれてるやつ。開発者はコードに書くことに集中でき、それ以外は Azure にお任せできる

Visual Studio 2017.3 に標準で Azure Function を開発するための拡張機能が追加されたので触ってみた感じ。

言語は C# を選んだ。 NodeJS を前提に作られてるっぽいけど、今回は Visual Studio 2017 の進化したインテリセンスを使ってみたくて、、、

Azure Table Storage とは

いわゆる、 NoSQL なデータベースで、 Key-Value な感じを採用してる。 今回は、 Azure Function と標準で対応してて相性がよさそうという理由で採用してる

CRUD

データベースに対する基本的な操作の データの作成 © 読み取り ® 更新 (U) 削除 (D) なのをまとめてそう呼んでいます。

実際にどうやるのか

今回操作していくデータ

テーブル名

storeInfo

カラム

  • Name
  • Locationx
  • Locationy

データの作成 ©

作成するテンプレート

Http-POST なテンプレートを使用して作成していきます。

f:id:kuxumarin:20170816140609p:plain

コード例

using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage.Table;

namespace FunctionApp1
{
    public static class PostStoreData
    {
        [FunctionName("PostStoreData")]
        public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post")]HttpRequestMessage req, [Table("storeInfo", Connection = "")]ICollector<Person> outTable, TraceWriter log)
        {
            dynamic data = await req.Content.ReadAsAsync<object>();
            string name = data?.name;
            double locationx = data?.locationx;
            double locationy = data?.locationy;

            if (name == null || locationx == 0 || locationy == 0)
            {
                return req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name in the request body");
            }

            outTable.Add(new Person()
            {
                PartitionKey = "Functions",
                RowKey = Guid.NewGuid().ToString(),
                Name = name,
                LocationX = locationx,
                LocationY = locationy
            });
            return req.CreateResponse(HttpStatusCode.Created);
        }

        public class Person : TableEntity
        {
            public string Name { get; set; }
            public double LocationX { get; set; }
            public double LocationY { get; set; }
        }
    }
}

データの読み込み ®

使用するテンプレート

Http-GET なテンプレートを使用して作りました。

f:id:kuxumarin:20170816174759p:plain

コード例

using System.Linq;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage.Table;

namespace FunctionApp1
{
    public static class GetStoreData
    {
        [FunctionName("GetStoreData")]
        public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Function, "get")]HttpRequestMessage req, [Table("storeInfo", Connection = "")]IQueryable<Person> inTable, TraceWriter log)
        {
            var query = from person in inTable select person;
            
            foreach (Person person in query)
            {
                log.Info($"Name:{person.Name}");
            }
            return req.CreateResponse(HttpStatusCode.OK, inTable.ToList());
        }

        public class Person : TableEntity
        {
            public string Name { get; set; }
            public double LocationX { get; set; }
            public double LocationY { get; set; }
        }
    }
}

データの更新 (U)

Http-PUT なテンプレートを使用し作りました

f:id:kuxumarin:20170816175006p:plain

コード例

using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage.Table;
using Newtonsoft.Json;
using System.Linq;

namespace FunctionApp1
{
    public static class UpdateStoreInfo
    {
        [FunctionName("UpdateStoreInfo")]
        public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Function, "put")]Person person, [Table("storeInfo", Connection = "")]CloudTable outTable, TraceWriter log)
        {
            if (string.IsNullOrEmpty(person.Name))
            {
                return new HttpResponseMessage(HttpStatusCode.BadRequest)
                {
                    Content = new StringContent("A non-empty Name must be specified.")
                };
            };

            log.Info($"PersonName={person.Name}");

            //outTable
            //    .CreateQuery<Person>()
            //    .Where(personData => personData.Name == "kuxu")
            //    .Select(personData => personData.PartitionKey)
            //    .ToList()
            //    .ForEach(partitionKey => ;

            TableOperation updateOperation = TableOperation.InsertOrReplace(person);
            TableResult result = outTable.Execute(updateOperation);
            return new HttpResponseMessage((HttpStatusCode)result.HttpStatusCode);
        }

        public class Person : TableEntity
        {
            public string Name { get; set; }
            public double LocationX { get; set; }
            public double LocationY { get; set; }
        }
    }
}

データの削除 (D)

Http-Trigger なテンプレートをもとに作りました。

f:id:kuxumarin:20170816175142p:plain

コード例

using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using static FunctionApp1.PostStoreData;
using System;
using Microsoft.WindowsAzure.Storage.Table;

namespace FunctionApp1
{
    public static class DeleteStoreInfo
    {
        [FunctionName("DeleteStoreInfo")]
        public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "delete", Route = null)]HttpRequestMessage req, [Table("storeInfo", Connection = "")] CloudTable inTable, TraceWriter log)
        {
            log.Info("C# HTTP trigger function processed a request.");

            dynamic data = await req.Content.ReadAsAsync<object>();

            string key = data?.key;
            string rowNumber = data?.rowNumber;

            if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(rowNumber))
                return req.CreateResponse(HttpStatusCode.BadRequest, "Argument Erro");

            var excuseResult = inTable.Execute((TableOperation.Delete(new TableEntity() { PartitionKey = key, ETag = "*"})));

            HttpStatusCode stateCode;

            if (excuseResult.HttpStatusCode.ToString().StartsWith("2"))
            {
                stateCode = HttpStatusCode.Accepted;
            }
            else
            {
                stateCode = HttpStatusCode.BadRequest;
            }
                
            return req.CreateResponse(stateCode, $"Code:{excuseResult.HttpStatusCode}");
        }
    }
}

値で検索してデータを返す

Http-GET なテンプレートを使用して作成

// 画像は省略

実行例

今回は、 データベースの中にすでに存在している name プロパティを参考に検索するコードを書いていきます。

検索するワードの指定は、 GET リクエストのURLの最後に name={検索したい文字} で指定しています。

既存のデータ

f:id:kuxumarin:20170817075847p:plain

検索結果

検索ワード: kuxu f:id:kuxumarin:20170817080043p:plain

検索ワード: chihiro f:id:kuxumarin:20170817080004p:plain

コード例

using System.Linq;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage.Table;

namespace FunctionApp1
{
    public static class SearchStoreInfo
    {
        [FunctionName("SearchStoreInfo")]
        public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Function, "get")]HttpRequestMessage req, [Table("storeInfo", Connection = "")]IQueryable<Person> inTable, TraceWriter log)
        {
            dynamic data = req.Content.ReadAsAsync<object>();


            string name = req.GetQueryNameValuePairs()
                             .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
                             .Value;

            if (string.IsNullOrWhiteSpace(name))
                return req.CreateResponse(HttpStatusCode.BadRequest, "Argument Not found");

            var searchResultList = inTable.Where(person => person.Name == name).ToList();

            if (searchResultList.Count == 0)
                return req.CreateErrorResponse(HttpStatusCode.NotFound, "Data Not Found");

            return req.CreateResponse(HttpStatusCode.OK, searchResultList);
        }

        public class Person : TableEntity
        {
            public string Name { get; set; }
        }
    }
}

感想

ちゃっと作るときは便利ですね~ 目的によっては強い子かも

未成年で Microsoft MVP アワード を初受賞しました!

2017/08 付けで Microsoft MVP アワード を初受賞しました。

カテゴリは Visual Studio and Development Technologies です。

19 歳で、学生のうちに受賞できて光栄です。

関係者各位ありがとうございます。

自分語りのポエムを書き残せる絶好の機会なので書いてみます。

Twitter

twitter.com

アマゾンの欲しいものリスト

www.amazon.co.jp

最近興味ある事

C#, Xamarin, TDD, Kotlin

はじまり

2015 年 7月に わんくま勉強会に参加したのが、コミュニティ活動の始まりでした。 あの頃の自分は、学校でパソコンについて興味の合う人がいなくてやさぐれかけていました。 WWDC で発表されたイケメンなものを語り合える人が欲しかった!

自分は、それまでに Microsoft の学生向けの施策である DreamSpark などを利用したりはしていましたが。とくに何をしたいとかはなく、適当にWindows Store App などのプログラムとかを作ってました。 初参加の勉強会がMicrosoft 系のであったのはよかったかもしれないです。

また、その勉強会では、 後々インターンシップやその他沢山のことでお世話になる 株式会社 Shaxware の社本さん (@sha256) や わんくま勉強会主催の You&Iさん(@you_and_i) , じぇいさん(@j_levia) などにお会いしました。

www.wankuma.com

CenterCLR 初参加

2015 年の 08/31 という当時、高校生だった自分はつらい日程でしたが参加した勉強会です。じぇいさんに誘われたので参加してきました。 じぇいさん以外の参加者は誰がいるのか知らない状況での参加でした。

その場では、 CenterCLR のオーガナイザーである kekyo氏 (@kekyo2) さんや 加藤さんや岐阜の可知さん、松岡さん、てるろーさん、平内さん、と初めて会いました。

特に、がりっちさんは参加者の中で一番年齢が近い人でした。MSPの存在を知ったのはがりっちさんからのその場が初めてでした。 帰りの電車が偶然一緒になったのですが、MSPについて熱く語ってるがりっちさんを見てました。

当時のブログ

kuxumarin.wpblog.jp

第13回まどべんよっかいち

まどべんよっかいちは、四日市が本拠地のMicrosoft系コミュニティです。そこでは、主催者ののぶくまさんやうえぽんさんと初めて会いました。 その会は名古屋での開催ということでした、たぶんよっかいちで開催してたら参加できなかったと思います。 でも、今ならいろいろなところへ行くのに慣れてるので!四日市行きますよ~!!!

ChalkTalk CLR – 動的コード生成技術(式木・IL等)

kekyo さんの主催した濃ゆい勉強会です。その場では、ぶれいすさんや大沼くんと初めて会いました。 今なら、ある程度理解することができる気がしますが、当時はいろいろな経験が少なく全く理解できなかったです…

ChalkTalk CLR – COMのすべて

今思えば、なんでこんな濃ゆい勉強会が名古屋でばっか開催されてたのだろうと思います。これも、 kekyo さん主催の勉強会です。 この会では、 渋木さんや石野さんと初めて会いました。それにしても参加者もすごかった。

C丼を食べた

松岡さんの奥さんありがとうございます!おいしかったです!

kuxumarin.hatenablog.com

NAWA Tech  ~ 気付けば3年目ですよ ~

Microsoft Azureのお堅い部分の勉強会です。覚えていただいているかはわかりませんが、 Microsoft エバンジェリストをやられていた 高添さんや SE の雑記の小澤さんと初めて会いました。

名古屋情報セキュリティ勉強会

この勉強会では、 まっちゃさんや一緒にMSPとして活動している影白くんと出会いました。

VSUG Final Days

Visual Studio User Group のイベントへの最初で最後の参加をしました。

インターンしていた会社の方が勢ぞろいしてパネルディスカッションしていたのは面白かったです。

このイベントは、Microsoft品川本社で開催され、 Microsoft MVP の方がたくさんいました。 JXUG でお世話になる田淵さんともここで会いました。Twitterでからんでいるしんじさんと実際に会いました。実際のしんじさんは17歳じゃなかった! Microsoft CTO の榊原さん、エバンジェリストの井上章さん、大西さんや翔泳社の岩切さん。 それだけではなく!いつもネットでは見たことがあるが、実際にはあったことのない、関さん、目代さん、亀川さん、とっちゃんさん、石坂さん、小島さん、じんぐるさん、中仙道さん、青柳さんと出会いました!

Microsoft MVP の方とお会いし、私の目指すべき場所はここだなと感じました。

実は、ここで「学生はVisual Studio を無料で使える!最高!」という内容でLTもさせていただきました。 Windows 98 と同じ年齢ネタが非常に受けました。

de;code 2016/2017

両年ともスタッフとして参加しました。

Microsoftエバンジェリストの大森さん、岩永さん、森口りえさんにはお世話になりました。

ここには書ききれないくらい沢山の方にお会いしました。 個人的には、かずあきさん(17)、ネットでフリー素材扱いされているだるやなぎさん、年齢が近くて、その後Microsoft MVP になった、大平さんにあったりしたのが印象に残っています。

JXUG と Xamarin と 千代田まどかさん

多分、Microsoft MVP に選ばれた理由の大半がここにあるかと思います。 私の初めての勉強会主催は、 JXUGC の名古屋開催の時でした。 名古屋(近辺)の有力者に手伝ってもらいながら、未熟ながらもなんとか主宰しました。

あめいさんとここで会いました。ともきさん、有地さん、土川さん、などの強い学生と沢山知り合えました。みんな強い。

f:id:kuxumarin:20170802022420p:plain

Xamarin がブームに乗っていることもあり、開催をすれば参加者募集の方は何も考えなくてもいい状況であったのは、勉強会主催する側としてはある意味で楽な状況でした。 (勉強会主催しても人があつまらなきゃ継続しにくい…)

また、 名古屋開催の2回目からは Microsoft エバンジェリストの千代田まどかさんに来ていただいたり、さまざまな面で協力いただいたりしました。 後述する MSP での活動でも援助いただいていて、感謝しています。

ハッカソン・HACKCHU・スタートアップウィークエンド

ハッカソンのメンターみたいな人として、津隈さんや大森さんと出会いました。 スタートアップウィークエンドでは、地元な型と沢山会いました。

Microsoft Student Partners

Microsoft Student Partners を 2017/01 からやっています。 ラルフさんやすごい人たちと会いました。

IoTLT

わみさんや松浦さん、いろいろ出会った!

JXUG 学生支部

JXUG に学生の人がもっと来てほしくて作りました! がりっちさんの作った、 JAZUG 学生支部を参考にしています!

IT欅坂48研究会

趣味を全開で語り合えるFacebookグループを作った! 木澤さんの表では見せない姿を見れた!(暴露

ふりかえって

MVP になるまでに様々な人の愛や運に恵まれていたと感じました。 リアル・Twitterなどで様々な方に支えられてきたので、少しでも恩返しができるようになりたいですね。

MVP になったからと言って何か変わるわけではありませんが、今まで通りゆるふわく活動していけたらいいと考えています。 自分のやりたいことを見つけて、それに向かって突撃していきたいです。

本当に各コミュニティの皆様、MVPの皆様、今までご支援いただきありがとうございました。

Amazon の欲しいものリスト

www.amazon.co.jp

a まともなコードをかける人になりたい!

今後の予定

今、したいこと

  • 「くぅ勉強会」を開く!(がりっち勉強会みたく!)
  • 東京で 学生LT を川島くんと主宰する
  • 川島くん、こうへいさんと朝まで語り合いたい。今度🍣🍕🍜をおごってくれるらしいので食べに行きます。
  • TDDBC に参加して TDD できるようになりたい
  • まどべんよっかいちに参加する(四日市に行く口実が欲しい

Android-Kotlin で Wifi のSSIDを取得する

class SSIDManager{
    fun GetSSID(ApplicationContext:Context): String{
        val wifiManager = ApplicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager

        if(!wifiManager.isWifiEnabled) return "";
        val connectInfo = wifiManager.connectionInfo

        val state = WifiInfo.getDetailedStateOf(connectInfo?.supplicantState)
        return when(state) {
            null -> ""
            NetworkInfo.DetailedState.CONNECTED, NetworkInfo.DetailedState.OBTAINING_IPADDR ->  wifiManager.connectionInfo.ssid
            else -> ""
        }
    }
}
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

実行結果

f:id:kuxumarin:20170802160708p:plain

第2回 学生エンジニア限定LT大会!!! でLTしてきました

第2回 学生エンジニア限定LT大会!!! でLTしてきました。

開催内容

学生エンジニア集まれ!!! 学生限定のLT大会です。大学生だけでなく、中学生や高校生も大歓迎です。 学生エンジニア同士の交流がメインなのでLTのテーマは特に無く、自由に話していただければと思います。 (プログラミング、Linux、セキュリティ、ビットコイン、好きな曲…) 参加費用は懇親会の費用となりますので、懇親会に参加しない方は払わなくて大丈夫です。 また、今回は最近まで学生だった方や、学生と混ざりたいと思っている大人の方向けに「学生じゃない枠」も用意しているので、学生じゃないから行けない!と思って…

詳しくは、こちら

日時

2017/07/29(土) 13:00 - 16:30

参加人数

37 人

当日の役割

LT

資料

[{TextURL}:embed:cite]

当日の様子など

www.slideshare.net

大同大学内のC# 勉強会で MSIL についての発表?ワークショップ?をしてきました。

大学で C# の勉強会が開催されるということで、参加ついでに発表してきました。

C# についてやるなら、ついでにILについても知っておいた方がいいよねーってことで、、、 ワークショップでは、 Visual Studio拡張機能である ILSPY を使って、IL を見ました。 Boxing と unboxing について浚ったあとに、 var で型情報が決まるのは、どのタイミングか。とかを確認しました。

資料

www.slideshare.net

Microsoft Forms について LT してきました。

Microsoft Forms とは、アンケートを取るためのツールです。 それを、「勉強会で運用した」と話してきました。

1drv.ms

moq で 非同期メソッドの返り値を設定する

やりかた

メソッドの返り値を設定するときに Returns の代わりに ReturnsAsync を使う。

コード

[TestFixture]
public class TestClass
{
    [Test]
    public async Task TestMethod()
    {
        var hogeMoq = new Mock<Ihoge>();
        hogeMoq.Setup(obj => obj.getHtml()).ReturnsAsync("Hello World");

        var Actual = await hogeMoq.Object.getHtml();

        Assert.AreEqual("Hello World", Actual);
    }
}

public interface Ihoge
{
    Task<string> getHtml();
}

public class hoge:Ihoge
{
    public async Task<string> getHtml()
    {
        using (var client = new HttpClient())
        {
            var result =await client.GetAsync("www.yahoo.co.jp");
            return await result.Content.ReadAsStringAsync();
        }
    }
}

https://lh3.googleusercontent.com/-0MTFJFZAl0s/WXMW-9eOJ4I/AAAAAAAALJo/T7MfQkatA7gVJRYwOSdl2WRoLs7JJCPCgCHMYCw/s0/devenv_2017-07-22_18-12-25.png