カテゴリー別アーカイブ: ASP.NET Web API

【F# + ASP.NET Web API】 JSONPでクロス ドメイン通信を行うには

◆ 参考

JSONPってなに?JSONP with ASP.NET Web API

◆ JSONP形式へ変換

namespace Sample.Web

open System
open System.IO
open System.Web
open System.Net
open System.Net.Http
open System.Net.Http.Formatting
open System.Net.Http.Headers
open System.Threading.Tasks

// JSONP形式へ変換
type JsonpMediaTypeFormatter() =
    inherit JsonMediaTypeFormatter()

    do
        base.SupportedMediaTypes.Add(JsonMediaTypeFormatter.DefaultMediaType)
        base.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"))
        base.MediaTypeMappings.Add(new UriPathExtensionMapping(
            "jsonp", JsonMediaTypeFormatter.DefaultMediaType))
    
    // コールバック・パラメータ(callback)
    let mutable _callbackQueryParameter = String.Empty
    member x.CallbackQueryParameter
        with get() = 
            if (_callbackQueryParameter.Equals(String.Empty)) then
                "callback"
            else
                _callbackQueryParameter
        and set v = _callbackQueryParameter <- v

    member val callback = String.Empty with get, set

    // URLにクエリ文字列「callback」が存在するか確認
    member x.IsJsonpRequest() =
        let test = HttpContext.Current.Request.HttpMethod

        // HTTP GET 以外の場合は、処理終了
        if (HttpContext.Current.Request.HttpMethod <> "GET") then
            false
        else
            // クエリ文字列「callback」を取得
            x.callback <- HttpContext.Current.Request.QueryString
                .[x.CallbackQueryParameter]            

            not(String.IsNullOrEmpty(x.callback))        

    member x.BaseWriteToStreamAsync(
        typeValue:Type, value:obj, writeStream:Stream
        ,content:HttpContent ,transportContext:TransportContext) =

        base.WriteToStreamAsync(
            typeValue, value, writeStream
            , content, transportContext).Wait()

    override x.WriteToStreamAsync(
        typeValue:Type, value:obj , writeStream:Stream 
        ,content:HttpContent ,transportContext:TransportContext) =

        if (x.IsJsonpRequest()) then
            // URLにクエリ文字列「callback」が存在する場合         
            Task.Factory.StartNew(fun () ->
                // JSONP形式 = "コールバック関数(JOSNデータ)" に変換
                use writer = new StreamWriter(writeStream)
                writer.Write(x.callback + "(")
                writer.Flush()
                x.BaseWriteToStreamAsync(typeValue, value
                    , writeStream, content, transportContext)
                writer.Write(")")
                writer.Flush()
            )            
        else
            base.WriteToStreamAsync(typeValue, value
                , writeStream, content, transportContext)

◆ Global.fs

namespace Sample.Web

open System
open System.Web
open System.Web.Mvc
open System.Web.Routing
open System.Web.Http
open System.Data.Entity

type Route = { controller : string
               action : string
               id : UrlParameter }

type MapHttpRouteSettings = { id : obj }

type Global() =
    inherit System.Web.HttpApplication() 

    static member RegisterGlobalFilters(filters:GlobalFilterCollection) =
        filters.Add(new HandleErrorAttribute())

    static member RegisterRoutes(routes:RouteCollection) =
        // 省略

    member this.Start() =
        AreaRegistration.RegisterAllAreas()
        
        // JSONP 形式変換を処理を適用
        let config = GlobalConfiguration.Configuration
        config.Formatters.Insert(0, new  JsonpMediaTypeFormatter())
        
        Global.RegisterGlobalFilters(GlobalFilters.Filters)
        Global.RegisterRoutes(RouteTable.Routes)

◆ Controller

namespace Sample.Web.Controllers

open System
open System.Web
open System.Web.Mvc
open System.Net.Http
open System.Web.Http
open System.Collections.Generic

// #r "System.Runtime.Serialization"
open System.Runtime.Serialization

// MongoDB 関連
open  MongoDB.Driver;
open  MongoDB.Driver.Builders
open  MongoDB.Bson
open  MongoDB.Bson.Serialization.Attributes

// JSONの型
[<DataContract>]
type SampleEntity() =
    [<BsonId>]
    member val _id = ObjectId.GenerateNewId() with get, set
    [<DataMember>]
    member val Name = String.Empty with get, set
    [<DataMember>]
    member val Age = Int32.MinValue with get, set
    
type SampleController() =
    inherit ApiController()

    member x.Get(name:string) = 
        // MongoDBへ接続
        let server = MongoServer.Create("mongodb://localhost/?safe=true")
        let db = server.GetDatabase("SampleDB")
        let collection = db.GetCollection<SampleEntity>("SampleTable")

        // 条件を指定して、ドキュメントを取得        
        let query = new QueryDocument();
        query.Add("Name", BsonString.Create(name))        
        |> ignore

        collection.Find(query)

◆ HTML(jQuery)

$(function () {
    $.ajax({            
        type: "GET",
        url: 'http://localhost:54465/api/Sample/Taro' + "?callback=?",
        data: {},
        dataType: 'jsonp',
        jsonp: 'jsoncallback',
        success: function (data) {
            //通信が成功した場合の処理 (JSONPのコールバック関数はこれが呼ばれます)
            alert('success');
        },
        error: function (data, status) {
            //通信終了時の処理
            alert('error');
        },
        complete: function (data) {
            //通信終了時の処理
            alert('complete');
        },
    });
});

【F# + ASP.NET Web API】 MongoDBへデータを挿入するには

◆ Controller

namespace FsWeb.Controllers

open System.Web
open System.Web.Mvc
open System.Net.Http
open System.Web.Http
// MongoDB 関連
open  MongoDB.Driver
open  MongoDB.Bson

type ValuesController() =
    inherit ApiController()
    
    member x.Post([<FromBody>] name:string, email:string) =
        // MongoDBへ接続
        let server = MongoServer.Create("mongodb://localhost/?safe=true")
        let db = server.GetDatabase("sample_db")        
        
        // 更新用データを作成
        let emement = [|new BsonElement("name", BsonString.Create(name));
                            new BsonElement("email", BsonString.Create(email))|]
        let user = new BsonDocument(emement)
        
        // コレクションを取得
        let users = db.GetCollection<BsonDocument>("users")        
        // データをを挿入
        users.Insert(user) |> ignore
        

【F# + ASP.NET Web API】 MongoDBからデータを取得するには

◆ 事前準備

・Nuget からOfficial MongoDB C# driver を導入

◆ Controller

namespace FsWeb.Controllers

open System.Web
open System.Web.Mvc
open System.Net.Http
open System.Web.Http
// #r "System.Runtime.Serialization"
open System.Runtime.Serialization
// MongoDB 関連
open  MongoDB.Bson.Serialization.Attributes
open  MongoDB.Driver.Builders
open  MongoDB.Driver
open  MongoDB.Bson

// JSONの型
[<DataContract>]
type User() =
    [<BsonId>]
    member val _id = ObjectId.GenerateNewId() with get, set
    [<DataMember>]
    member val name = "" with get, set
    [<DataMember>]
    member val email = "" with get, set

type ValuesController() =
    inherit ApiController()
    member x.Get() =
        // MongoDBへ接続
        let server = MongoServer.Create("mongodb://localhost/?safe=true")
        let db = server.GetDatabase("sample_db")        
        // コレクションを取得
        let users = db.GetCollection<User>("users")
        // 条件を指定して、ドキュメントを取得
        let query = Query.And(Query.EQ("name", BsonString.Create("Jiro")))
        users.FindOne(query)

★Windows Store apps(JavaScript) + KnockoutJS + ASP.NET Web API(F#) による開発を行うには

◆ 事前準備

1. Windowsストア ・プロジェクト(JavaScript)を新規作成
2. Windowsストア ・プロジェクトに KnockoutJS を導入
3. Windowsストア ・プロジェクトに jQuery を導入
4. オンラインテンプレート "F# C# MVC 4" を元に ASP.NET Web API プロジェクトを追加。


◆ Windowsストア ・プロジェクト

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta charset="utf-8" />
    <title>Sample</title>

    <!-- WinJS 参照 -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>

    <!-- KnockoutJS & jQuery 参照 -->
    <script src="Scripts/knockout-2.1.0.debug.js"></script>
    <script src="Scripts/jquery-1.8.1.js"></script>    
</head>
<body>
    <button id="Exec">実行</button>
    <ul data-bind="template: { foreach: DataList }">
        <!-- KnockoutJS によるデータ・バインド -->
        <li><span data-bind="text: Id"></span></li>
    </ul>

    <script type="text/javascript">
        // ViewModel
        var data = [];
        var viewModel = {
            DataList: ko.observableArray(data)
        };
        ko.applyBindings(viewModel);

        $(function () {
            // 実行ボタン クリック処理
            $('#Exec').click(function () {
                // ASP.NET Web APIの呼び出し
                $.ajax({
                    url: 'http://localhost:59885/api/values',
                    dataType: 'json',
                    success: function (data) {
                        viewModel.DataList(data);
                    }
                });
            });
        });
    </script>
</body>
</html>


◆ ASP.NET Web API(F#) プロジェクト

namespace FsWeb.Controllers

open System.Web
open System.Web.Mvc
open System.Net.Http
open System.Web.Http
// #r "System.Runtime.Serialization"
open System.Runtime.Serialization

// データ型
[<DataContract>]  
type Model =  
    { [<DataMember>] Id : string }

type ValuesController() =
    inherit ApiController()
    
    // JSON形式で取得
    member x.Get()
        = [| { Id = "hoge1" }; { Id = "hoge2" }; { Id = "hoge3" } |]