适用于asp.net mvc的AMF ActionResult

时间:2012-04-02 10:02:53

标签: asp.net-mvc flash amf actionresult

我正在构建一个mvc应用程序,它将通过AMF与flash通信, 任何人都知道网上是否有 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());
        }
    }
}

但闪存方面的响应处理程序没有被击中。

在<{3}}的响应 - &gt; Amf标签中的

我看到了这个错误:

  

无法解析数据(com.xk72.amf.AMFException:不支持的AMF3数据包类型17在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

和Hex标签:

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            

3 个答案:

答案 0 :(得分:2)

诀窍是将FluorineFx.IO.AMFMessage与AMFBody一起用作结果对象并设置Content属性。

你可以在Charles代理中看到这个与其他工作示例(我使用了很棒的WebORB examples,特别是Flash remoting Basic Invocation AS3

我已更新AMFFilter以支持AMFBody需要的Response参数。也许它可以通过一些当前的上下文缓存更优雅地解决,不知道。

代码如下:

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就删除它。

BTW,你真的需要在ASP.NET MVC中使用它吗?也许简单的ASHX处理程序就足够了,性能会更好,我不知道。 MVC架构是我认为的优点。

答案 1 :(得分:1)

我没有看到在网络上实施的ActionResult,但有FluorineFX.NET支持AMF。

答案 2 :(得分:1)

AFAIK没有AMF ActionResult的任何实现,但您可以使用FluorineFx.NET sources

中的类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);
        }
    }
}