1

私はAMFを介してフラッシュと通信するMVCアプリケーションを構築していますが、Web上で利用可能なAMF ActionResultがあるかどうかは誰にもわかりませんか?

編集

@mizi_sk回答を使用して(ただし、IExternalizableを使用せずに)このActionResultを実行しました:

public class AmfResult : ActionResult
{
    private readonly object _o;

    public AmfResult(object o)
    {
        _o = o;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.ContentType = "application/x-amf";
        using (var ms = new MemoryStream())
        {
            // write object
            var writer = new AMFWriter(ms);
            writer.WriteData(FluorineFx.ObjectEncoding.AMF3, _o);
            context.HttpContext.Response.BinaryWrite(ms.ToArray());
        }
    }
}

ただし、フラッシュ側の応答ハンドラーはヒットしません。

Charlesの[応答]->[Amf]タブで、次のエラーが表示されます。

データの解析に失敗しました(com.xk72.amf.AMFException:サポートされていないAMF3パケットタイプ17 at 1)

これは生のタブです:

 HTTP/1.1 200 OK 
 Server: ASP.NET Development Server/10.0.0.0 
 Date: Mon, 14 May 2012 15:22:58 GMT 
 X-AspNet-Version: 4.0.30319
 X-AspNetMvc-Version: 3.0 
 Cache-Control: private 
 Content-Type:application/x-amf 
 Content-Length: 52 
 Connection: Close

  3/bingo.model.TestRequest param1coins name

および[16進]タブ:

00000000  11 0a 33 2f 62 69 6e 67 6f 2e 6d 6f 64 65 6c 2e     3/bingo.model.
00000010  54 65 73 74 52 65 71 75 65 73 74 0d 70 61 72 61   TestRequest para
00000020  6d 31 0b 63 6f 69 6e 73 09 6e 61 6d 65 01 04 00   m1 coins name   
00000030  06 05 6a 6f                                         jo            
4

3 に答える 3

2

コツはFluorineFx.IO.AMFMessage、AMFBody を結果オブジェクトとして使用し、Contentプロパティを設定することです。

これは、Charles プロキシで他の作業例とともに確認できます (私は優れたWebORB の例、特にFlash remoting Basic Invocation AS3を使用しました) 。

AMFFilter を更新しResponseて、AMFBody が必要とするパラメーターをサポートするようにしました。たぶん、現在のコンテキストキャッシュによってよりエレガントに解決できるかもしれませんが、わかりません。

コードは次のとおりです。

public class AmfResult : ActionResult
{
    private readonly object _o;
    private readonly string _response;

    public AmfResult(string response, object o)
    {
        _response = response;
        _o = o;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.ContentType = "application/x-amf";

        var serializer = new AMFSerializer(context.HttpContext.Response.OutputStream);
        var amfMessage = new AMFMessage();
        var amfBody = new AMFBody();
        amfBody.Target = _response + "/onResult";
        amfBody.Content = _o;
        amfBody.Response = "";
        amfMessage.AddBody(amfBody);
        serializer.WriteMessage(amfMessage);
    }
}

これを機能させるには、コントローラーのメソッドを AMFFilter でデコレートする必要があります

public class AMFFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Request.ContentType == "application/x-amf")
        {
            var stream = filterContext.HttpContext.Request.InputStream;

            var deserializer = new AMFDeserializer(stream);
            var message = deserializer.ReadAMFMessage();

            var body = message.Bodies.First();
            filterContext.ActionParameters["target"] = body.Target;
            filterContext.ActionParameters["args"] = body.Content;
            filterContext.ActionParameters["response"] = body.Response;

            base.OnActionExecuting(filterContext);
        }
    }
}

これは次のようになります

[AMFFilter]
[HttpPost]
public ActionResult Index(string target, string response, object[] args)
{
    // assume target == "TestMethod" and args[0] is a String
    var message = Convert.ToString(args[0]);
    return new AmfResult(response, "Echo " + message);
}

参照用のクライアント側コード

//Connect the NetConnection object
var netConnection: NetConnection = new NetConnection();
netConnection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
netConnection.connect("http://localhost:27165/Home/Index");

//Invoke a call
var responder : Responder = new Responder( handleRemoteCallResult, handleRemoteCallFault);
netConnection.call('TestMethod', responder, "Test");

private function onNetStatus(event:NetStatusEvent):void {
    log(ObjectUtil.toString(event.info));
}

private function handleRemoteCallFault(...args):void {
    log(ObjectUtil.toString(args));
}

private function handleRemoteCallResult(message:String):void {
    log(message);
}

private static function log(s:String):void {
    trace(s);
}

エラーを返したい場合は、AMFResult のこの行を変更するだけです

amfBody.Target = _response + "/onFault";

私は ObjectUtil.toString() フォーマットが好きですが、Flex をリンクしていない場合は削除してください。

ところで、ASP.NET MVC でこれが本当に必要ですか? シンプルな ASHX ハンドラーで十分で、パフォーマンスが向上するかもしれませんが、わかりません。MVC アーキテクチャはプラスだと思います。

于 2012-05-14T19:16:30.090 に答える
1

Web で実装された ActionResult は見たことがありませんが、AMF をサポートするFluorineFX.NETがあります。

于 2012-04-03T06:18:03.257 に答える
1

私の知る限り、AMF ActionResult の実装はありませんが、 FluorineFx.NET ソースFluorineFx.IO.AMFWriterからクラスを使用して独自のクラスを作成できます。

どこか (github など) でオープンソース プロジェクトを作成することを検討してください。

編集 1 - サンプル

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluorineFx.IO;
using System.IO;
using FluorineFx.AMF3;
using System.Diagnostics;

namespace AMF_SerializationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var ms = new MemoryStream();

            // write object
            var writer = new AMFWriter(ms);
            writer.WriteData(FluorineFx.ObjectEncoding.AMF3, new CustomObject());

            Debug.Assert(ms.Length > 0);

            // rewind
            ms.Position = 0;

            // read object
            var reader = new AMFReader(ms);
            var o = (CustomObject)reader.ReadData();

            // test
            Debug.Assert(o.I == 3);
            Debug.Assert(o.S == "Hello");
        }
    }   

    public class CustomObject : IExternalizable
    {
        private int i = 3;

        public int I
        {
            get { return i; }
        }

        private string s = "Hello";

        public string S
        {
            get { return s; }
        }

        public void ReadExternal(IDataInput input)
        {
            i = input.ReadInt();
            s = input.ReadUTF();
        }

        public void WriteExternal(IDataOutput output)
        {
            output.WriteInt(i);
            output.WriteUTF(s);
        }
    }
}
于 2012-04-03T10:53:43.003 に答える