@dhq_boiler

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

[ASP.NET]OnPost()が実行されない

解決したいこと

ASP.NET Coreで"WinDesktopAppOnCloud"というWebシステムを作ろうとしています。
このWebシステムを簡単に説明します。
このプロジェクトはWindowsデスクトップアプリケーション(Windows FormsやWPFのアプリ)のソースコードをクラウド上のWindowsサーバーで(git)クローンして、MSBuildでビルドして、あわよくばデバッグしようという企みです。デバッグの仕組みはWindowsサーバー上でターゲットアプリケーションのプロセスを起動し、リアルタイムでPrintScreenし、Webシステム上に描画します。Webシステム上ではマウスポインタの移動イベントやクリックイベント、ドラッグ、キーイベント等が検知され、ターゲットアプリケーションのプロセスにSendMessageで伝えます。

※当システムは開発中なので、ターゲットアプリケーションは私が別のプロジェクトで開発しているboiler's Graphicsに仮で設定しています。

2021-07-20.png

↑boiler's GraphicsのPrintScreenの結果をWebシステム上に表示している

発生している問題・エラー

今、ターゲットアプリケーションのプロセスを起動し、最初の1枚のPrintScreenをして、Webシステム上に描画することに成功しました。

この後、Webシステム上に描画されたPrintScreenした画像上をマウスポインタが移動した時、Ajaxが動作し、/にPOSTしますが、IndexModel.OnPost()にブレークポイントを設定しても、ブレークされません。

おそらく、POSTの設定が何か足りてないと思うのですが、どうすればPOSTした時OnPost()が実行されるようになるでしょうか。

ソースコードの一部を載せます。

Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

namespace WinDesktopAppOnCloud.Pages
{
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;
        private Process _process;

        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }

        private bool PrevInstance()
        {
            var processes = Process.GetProcessesByName("boilersGraphics");
            if (processes.Length >= 1)
                return true;
            else
                return false;
        }

        public void OnGet()
        {
            StartDesktopAppProcessAndPrintScreen();
        }

        private void StartDesktopAppProcessAndPrintScreen()
        {
            if (PrevInstance() == false)
            {
                var app = new ProcessStartInfo();
                app.FileName = @"Z:\Git\boilersGraphics\boilersGraphics\bin\Debug\boilersGraphics.exe"; //将来的にはビルドシステムも搭載して、GitHubからソースコードをクローンして自鯖でビルドしてオンラインデバッグできるようにする
                _process = Process.Start(app);
                Thread.Sleep(1000);
            }

            if (_process == null)
            {
                _process = Process.GetProcessesByName("boilersGraphics").First();
            }

            IntPtr hWnd = _process.MainWindowHandle;
            while (hWnd == IntPtr.Zero)
            {
                _process.Refresh();
                hWnd = _process.MainWindowHandle;
            }
            IntPtr winDC = GetWindowDC(hWnd);
            //ウィンドウの大きさを取得
            RECT winRect = new RECT();
            GetWindowRect(hWnd, ref winRect);
            //Bitmapの作成
            Bitmap bmp = new Bitmap(winRect.right - winRect.left,
                winRect.bottom - winRect.top);
            //Graphicsの作成
            Graphics g = Graphics.FromImage(bmp);
            //Graphicsのデバイスコンテキストを取得
            IntPtr hDC = g.GetHdc();

            PrintWindow(hWnd, hDC, 0);
            //Bitmapに画像をコピーする
            BitBlt(hDC, 0, 0, bmp.Width, bmp.Height,
                winDC, 0, 0, SRCCOPY);
            //解放
            g.ReleaseHdc(hDC);
            g.Dispose();
            ReleaseDC(hWnd, winDC);

            MemoryStream ms = new MemoryStream();
            bmp.Save(ms, ImageFormat.Jpeg);
            var array = ms.ToArray();
            ms.Close();

            ViewData["ImgSrc"] = String.Format("data:image/jpeg;base64,{0}", Convert.ToBase64String(array));
        }

        public void OnPost()
        {
            //SendMessageでマウスポインタが移動したことをDesktopApp側に伝える
            SendMessage(_process.MainWindowHandle, WM_MOUSEMOVE, 0x0, PointToParam(JsonToPoint()));
        }

        private uint PointToParam(Point point)
        {
            return (uint)((int)point.X << 8 & (int)point.Y);
        }

        private Point JsonToPoint()
        {
            StreamReader reader = new StreamReader(Response.Body);
            var obj = JsonConvert.DeserializeObject(reader.ReadToEnd());
            var point = new Point();
            //TODO point.X = obj.X;
            //TODO point.Y = obj.Y;
            return point;
        }

        private const int SRCCOPY = 13369376;
        private const int CAPTUREBLT = 1073741824;

        [DllImport("user32.dll")]
        private static extern IntPtr GetDC(IntPtr hwnd);

        [DllImport("gdi32.dll")]
        private static extern int BitBlt(IntPtr hDestDC,
            int x,
            int y,
            int nWidth,
            int nHeight,
            IntPtr hSrcDC,
            int xSrc,
            int ySrc,
            int dwRop);

        [DllImport("user32.dll")]
        private static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);


        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        [DllImport("user32.dll")]
        private static extern IntPtr GetWindowDC(IntPtr hwnd);

        //[DllImport("user32.dll")]
        //private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        private static extern int GetWindowRect(IntPtr hwnd,
            ref RECT lpRect);

        [DllImport("User32.dll")]
        private extern static bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags);

        //送信するためのメソッド(文字も可能)
        [DllImport("User32.dll", EntryPoint = "SendMessage")]
        public static extern long SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);

        public const int WM_MOUSEMOVE = 0x0200;
        public const int WM_LBUTTONDOWN = 0x201;
        public const int WM_LBUTTONUP = 0x202;
        public const int MK_LBUTTON = 0x0001;
    }
}
Index.cshtml
@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<script type="text/javascript">
    window.onload = function () {
        $('#appFace').on('mousemove', function (e) {
            var mX = e.pageX;
            var mY = e.pageY;
            $.ajax({
                type: "POST",
                url: "/",
                cache: false,
                dataType: "json",
                data: { x: mX, y: mY },
                async: false,
                success: function (data) {
                    console.log("success");
                }
            });
        });
    }
</script>

<div class="text-center">
    <a href="" data-ajax="true" data-ajax-url="/index/partial" data-ajax-update="#panel">Click here</a>
    <div id="panel">
        <img id="appFace" src="@ViewData["ImgSrc"]" />
    </div>
</div>

Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace WinDesktopAppOnCloud
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromSeconds(10);
                options.Cookie.HttpOnly = true;
                options.Cookie.IsEssential = true;
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseSession();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
                endpoints.MapPost("/", async context =>
                {
                    int x = int.Parse(context.Request.Form["X"]);
                    int y = int.Parse(context.Request.Form["Y"]);
                    await context.Response.WriteAsJsonAsync(new { X = x, Y = y });
                });
            });

        }
    }
}

ソースコード

WinDesktopAppOnCloud
https://github.com/dhq-boiler/WinDesktopAppOnCloud

git repository
https://github.com/dhq-boiler/WinDesktopAppOnCloud.git

コミット:b0f8050

自分で試したこと

[HttpPost]属性をOnPost()につけてみましたが、警告がでました。

MVC1002: 'HttpPostAttribute' cannnot be applied to Razor Page handler methods. Routes for Razor Pages must be declared using the @page directive or using conventions.

Razor Pagesのルートは@pageディレクティブかusing conventionsを使って宣言しなければなりません、とありますが言ってることが理解できませんでした。

0 likes

2Answer

下記のように変更したら、OnPost()でブレークポイントが引っかかるようになりました。
endpoints.MapPost()していたのがいけなかったようですね。

Startup.cs
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
-                endpoints.MapPost("/", async context =>
-                {
-                    int x = int.Parse(context.Request.Form["X"]);
-                    int y = int.Parse(context.Request.Form["Y"]);
-                    await context.Response.WriteAsJsonAsync(new { X = x, Y = y });
-                });
            });
Index.cshtml
:
<div class="text-center">
    <form id="main" method="post">
        @Html.AntiForgeryToken()
        <a href="" data-ajax="true" data-ajax-url="/index/partial" data-ajax-update="#panel">Click here</a>
        <div id="panel">
            <img id="appFace" src="@ViewData["ImgSrc"]" />
        </div>
    </form>
</div>

0Like

Your answer might help someone💌