1

我正在构建一个 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());
        }
    }
}

但闪存端的响应处理程序没有受到打击。

Charles的 Response->Amf 选项卡中,我看到了这个错误:

解析数据失败(com.xk72.amf.AMFException: Unsupported AMF3 packet type 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

和十六进制选项卡:

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.AMFMessageAMF Body 作为结果对象并设置一个Content属性。

您可以在 Charles 代理中看到这一点以及其他工作示例(我使用了很棒的WebORB 示例,特别是Flash 远程处理基本调用 AS3

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

代码如下:

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

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

于 2012-04-03T06:18:03.257 回答
1

AFAIK 没有 AMF ActionResult 的任何实现,但您可以使用FluorineFx.IO.AMFWriter来自FluorineFx.NET 源的类创建自己的

考虑在某处创建一个开源项目(例如在 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 回答