スキップしてメイン コンテンツに移動

[ASP.NET Web Forms][TypeScript] Send data, call functions

Intro

Recently, I often update ASP.NET Web Forms application in my work.
Because Web Forms won't be supported in .NET 5, so I want to replace them into MVC.
Introducing .NET 5 | .NET Blog

I hope I can rebuild the projects from the beginning, but it's a little difficult.
The reasons are like the bugets, there are many "Big ball of mud", and so on.

So now, I try to organize to reduce burden for replace in the future.
This time, to change from Web Forms to HTML(reduce the Web Forms functions from View), I try to interact between Web Forms(+ code behind) and TypeScript.

Environments

  • ASP.NET ver.4.5.2
  • TypeScript ver.3.8.3
  • webpack ver.4.42.1

package.json


{
  "scripts": {
    "webpack": "npx webpack -w"
  },
  "dependencies": {
    "rxjs": "^6.5.4",
    "ts-loader": "^6.2.2",
    "tsc": "^1.20150623.0",
    "typescript": "^3.8.3",
    "webpack": "^4.42.1",
    "webpack-cli": "^3.3.11",
    "whatwg-fetch": "^3.0.0"
  }
}

webpack.config.js


var path = require('path');

module.exports = {
    mode: 'development',
    entry: {
        'main': './src/ts/main-page.ts',
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/
            }
        ]
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js']
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, './dist/js'),
        library: 'Page',
        libraryTarget: 'umd'
    }
}


Call from Web Forms(code behind)

I can call JavaScript functions from code behind of Web Forms in several ways.

DOM events

I can call JavaScript functions by button of Web Forms.

Default.aspx


<%@ Page Title="Home Page" Language="VB" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.vb" Inherits="WebApplication1._Default" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
    <p>
        <asp:TextBox ID="AspSampleText" runat="server">Hello</asp:TextBox>
        <asp:Button ID="CallSampleButton" runat="server" Text="Button" />
    </p>
    <script type="text/javascript" src="dist/js/main.bundle.js"></script>
</asp:Content>


Default.aspx.vb


Imports System.IO
Imports Newtonsoft.Json

Public Class _Default
    Inherits Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load        
        Dim message As New Message
        message.Message = "Hello Button!"
        Dim jsonMessage = JsonConvert.SerializeObject(message)
        CallSampleButton.OnClientClick = "return Page.callFromButton(" & jsonMessage & ")"
    End Sub
End Class

Message.vb


Public Class Message
    Public Property Message As String
End Class

I create JSON string by Newtonsoft.Json to set arguments.
Serialize an Object - Json.NET Documentation

main-page.ts


import { Message } from "./message";
export function callFromButton(message: Message): string {
    console.log(`Call button ${message}`);
    return 'hello button';
}

message.ts


export interface Message {
    message: string;
}

It's very simple to write. But I have problems caused by "Post Back".
When I click the button, althogh the event will be fired, but the page will be reloaded.
And some JavaScript codes will be removed.

And even if I don't use the button of ASP.NET(asp:Button), if I use button tag(<button>), the "Post Back" will be fired.

So I can't use buttons on aspx.

RegisterStartupScript

Another way to call JavaScript functions is using RegisterStartupScript.
ClientScriptManager.RegisterStartupScript Method - Microsoft Docs

Default.aspx.vb


Imports System.IO
Imports Newtonsoft.Json

Public Class _Default
    Inherits Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        Dim scriptManager As ClientScriptManager = Page.ClientScript
        Dim myType As Type = Me.GetType()
        If Not scriptManager.IsStartupScriptRegistered(myType, "StartupSample") Then
            Dim startupMessage As New Message
            startupMessage.Message = "Hello Startup!"
            Dim jsonStartupMessage = JsonConvert.SerializeObject(startupMessage)

            Dim registerScript = GenerateCallMethodScript("callFromStartup", jsonStartupMessage)
            scriptManager.RegisterStartupScript(myType, "StartupSample", registerScript)
        End If
    End Sub
    Private Function GenerateCallMethodScript(methodName As String, jsonArgument As String) As String
        Dim builder As New StringBuilder
        With builder
            .Append("<script type=""text/javascript"">")
            .Append("Page." & methodName & "(" & jsonArgument & ");")
            .Append("</script>")
        End With
        Return builder.ToString()
    End Function
End Class


If I want to use script block like below, I can use RegisterClientScriptBlock.
ClientScriptManager.RegisterClientScriptBlock Method - Microsoft Docs

Default.aspx.vb


Imports System.IO
Imports Newtonsoft.Json

Public Class _Default
    Inherits Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        Dim scriptManager As ClientScriptManager = Page.ClientScript
        Dim myType As Type = Me.GetType()
        If Not scriptManager.IsStartupScriptRegistered(myType, "StartupSample") Then
            
            Dim registerScript = GenerateCallMethodScript("callFromStartup")
            scriptManager.RegisterClientScriptBlock(myType, "StartupSample", registerScript)
        End If
    End Sub
    Private Function GenerateCallMethodScript(methodName As String) As String
        Dim builder As New StringBuilder
        With builder
            .Append("<script type=""text/javascript"">")
            .Append("function " & methodName & " () { alert('Hello'); }")
            .Append("</script>")
        End With
        Return builder.ToString()
    End Function
End Class

Call from TypeScript (JavaScript)

I can use "Generic Handler" to call ASP.NET functions from TypeScript.
Generic Handler ashx file : Post send JSON data in Asp.net c#, jQuery | Codepedia

SampleHandler.ashx


<%@ WebHandler Language="VB" CodeBehind="SampleHandler.ashx.vb" Class="WebApplication1.SampleHandler" %>


SampleHandler.ashx.vb


Imports System.IO
Imports System.Web
Imports System.Web.Services
Imports Newtonsoft.Json

Public Class SampleHandler
    Implements System.Web.IHttpHandler

    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        Dim gotValue As String = New StreamReader(context.Request.InputStream).ReadToEnd()
        If String.IsNullOrEmpty(gotValue) Then
            Console.WriteLine("Failed")
        Else
            Dim message As Message = JsonConvert.DeserializeObject(Of Message)(gotValue)
            If IsNothing(message) Then
                Console.WriteLine("FailedConvert")
            Else
                Console.WriteLine("OK " & message.Message)
            End If
        End If

        context.Response.ContentType = "text/plain"
        context.Response.Write("Hello World!")
    End Sub
    ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

End Class

main-page.ts


import { Message } from "./message";
import 'whatwg-fetch';

async function callGenericHandler() {
    await window.fetch('/SampleHandler.ashx',
        {
            mode: 'cors',
            method: 'POST',
            headers: {
                "Content-Type": "application/json; charset=utf-8",
            },
            body: JSON.stringify({message: 'Hello General Handler!'})
        })
        .then((response) => console.log(`RESPONSE: ${response}`))
        .catch((error) => console.error(error));
}
callGenericHandler();

Using Fetch - Web APIs | MDN

I can call "Generic Handler" to interact DB. It's like accessing controller of MVC.
But how about if I want to feedback to code behind(aspx.vb)?

I can call aspx instead of ashx.
But when I call it, the page will be reloaded.

So if I want to use TypeScipt, I think I have to remove all events of ASP.NET.

コメント

このブログの人気の投稿

[Nest.js] Show static files

Intro I wanted to use Nest.js and WebRTC(node-webrtc). NestJS - A progressive Node.js framework Documentation | NestJS - A progressive Node.js framework And because I wanted to try with simple page(not use JavaScript frameworks), I added static HTML, CSS, JavaScript into a Nest.js project. Prepare Install First, I installed @nestjs/cli. First steps | NestJS - A progressive Node.js framework As same as last time , I couldn't do global install because I had used Volta. But I could installed by volta. volta install @nestjs/cli Create project nest new nest-web-rtc-sample volta pin node@12 Run npm start After doing "npm start", I could getting "Hello World!" from http://localhost:3000. Add static files I could add static files by two ways. @nestjs/serve-static First one of them was using "serve-static". Serve Static | NestJS - A progressive Node.js framework npm install --save @nestjs/serve-static And I needed adding a module into app.modu

[Angular][ASP.NET Core] Upload chunked files

Intro I wanted to send files to Web application (made by ASP.NET Core). If the file size had been small, I didn't need do any special things. But when I tried to send a large file, the error was occurred by ASP.NET Core's limitation. Though I could change the settings, but I didn't want to do that, because I hadn't known the file sizes what would been actually using. So I splitted the data into chunks first, and sent them. After receiving all chunks, I merged them into one file. There might be some libraries or APIs (ex. Stream API) what did them automatically, but I couldn't find them. What I did [ASP.NET Core] Make CORS enabled [Angular] Split a large file into chunks [Angular][ASP.NET Core] Send and receive data as form data [ASP.NET Core] Merge chunks into one file [ASP.NET Core] Make CORS enabled Because the client side application(Angular) and the server side application(ASP.NET Core) had been separated, I had to make CORS(Cross-Origin Requests)

[Nest.js] Use WebSocket with ws

Intro Until last time , I had used node-web-rtc to try WebRTC. But because the example was a little complicated for I understood the core functions of using WebRTC. So I look for other frameworks or libraries. PeerJS is a famous library for WebRTC. peers/peerjs: Peer-to-peer data in the browser. - GitHub peers/peerjs-server: Server for PeerJS - GitHub PeerJS - Simple peer-to-peer with WebRTC A problem is I don't know how to integrate to the Nest.js project. I couldn't find examples. So I don't choose at least this time. What shall I choose? According MDN, WebRTC doesn't specify strictly what technology is used on server application for connecting two devices. Signaling and video calling - Web APIs | MDN But in many examples include MDN's one use WebSocket. samples-server/s/webrtc-from-chat at master · mdn/samples-server · GitHub So I try WebSocket in the Nest.js project. Use WebSocket in a Nest.js project Nest.js has a function for using We