LogoLogo
WinForms to WebPowerBuilder to .NETPowerBuilder to Java
  • WebMAP Documentation | Mobilize.Net
  • WinForms
    • Introduction
    • Getting Started
    • Conversion Process
    • Post-Conversion
    • Extend or Modify the Converted Application
      • NoWebMap Forms Winforms
        • How to add a new Form
        • Adding the created form to the migrated App
        • Interacting with the application data
        • Call the custom API
        • Interaction between the no webmap added Form and the WebMap components
      • Adding a component
      • Adding a component dynamically
      • Add a new control model
      • Switching CSS theme
      • Adding new window
      • Conversion Configuration
        • WebMAP configuration file
        • Stub Filter
      • Adding Non-WebMap Angular Forms
      • Adding FrontEnd Handler to a ToolStripMenuItem
      • Changing ToolStripButton icons
      • Adding new items to existing toolbar
      • Adding FrontEnd element properties and JS listeners
      • Adding FrontEnd output handlers
      • Access FrontEnd components
      • Create custom components based on existing WebMap Component
      • Override FrontEnd methods
    • Assessment Mode
    • Errors and Troubleshooting
      • How to resolve broken reference problems with VBUC
    • Portability
    • Glossary
    • Release Notes
    • Internal Demos
    • Known Issues
    • WinForms DCP
  • WebForms
    • Introduction
    • Overview
    • Desktop Compatibility Platform (DCP)
      • Pages and Master Pages
      • GridView and DataList data synchronization
      • HTTP objects
    • Post-Conversion
    • Extend or Modify the Converted Application
      • Adding FrontEnd validator
      • Adding Page
      • Adding MasterPage
    • Designer classes on WebForms Conversion Tool
    • Errors and Troubleshooting
      • How fix Solution when have been added website from filesystem without project file
    • Release Notes
  • PowerBuilder to .Net
    • Introduction
    • Getting Started
      • Conversion Tool
    • Desktop Compatibility Platform (DCP)
      • Data Manager
    • Reports
      • Report Rendering in Modernized Code
      • ReportWatcher Service Configuration
      • Data Manager to RDL Conversion
      • Reporting Service Internals
      • Troubleshooting
  • PowerBuilder to Java
    • Introduction
    • Getting started
    • Post-Conversion
      • Setup PBJava Environment
      • Architecture
      • App Start
    • Glossary
    • Errors
    • Glossary
    • FAQ
      • How to create a new Control
      • How to create a new Screen
      • What is the Mobilize.WebMAP.CoreServices.All?
      • What is the DesignerAttribute?
      • What is the InterceptedAttribute?
      • What is the InterceptedAttribute?
      • What is the ObservableAttribute?
      • What is the Mobilize.Weaving.WebMAPExtensions.All?
  • General
    • FrontEnd
      • Documentation
        • Webforms Angular Components
          • Web Components
            • Base Components
              • BaseValidator Component
            • KendoUI Components
              • CompareValidator
              • CustomValidator
              • RegularExpressionValidator
              • RequiredFieldValidator
              • ValidationSummary
          • Directives
          • AJAX Web Components
            • AjaxCalendar
            • AjaxModalPopupExtender
          • Ajax Interaction Services
        • Client Core
          • WebMap's Client Core
        • Angular Client
          • Introduction
          • WebMap Service
          • WebMap Interceptor Service
        • Base Components
          • Introduction
          • Components
            • Container
            • Control
            • ControlContainer
            • FormsContainer
            • Loading
            • Stub
        • Winforms Angular Components
          • Web Components
            • Base Components
              • Control Component
              • Form Container
              • Grid Component
              • Style
            • KendoUI Components
              • AdoDataControl
              • Button
              • C1TrueDBGrid
              • CheckBox
              • CheckedListBox
              • ComboBox
              • ContextMenuStrip
              • DataGridView
              • DataGridViewFlex
              • DateTimePicker
              • FileDialog
              • GroupBox
              • Label
              • ListBox
              • ListView
              • MaskedTextBox
              • MessageBox
              • NumericUpDown
              • Panel
              • PictureBox
              • PrintDialog
              • ProgressBar
              • RadioButton
              • RichTextBox
              • StatusStrip
              • Stup
              • TabControl
              • TabPage
              • TextBox
              • Timer
              • ToolStrip
              • TreeView
              • WebBrowser
              • Window
            • JQuery Web Components
          • WebMap FrontEnd Architecture
          • Migrated Structure
          • Setup
            • Front-End setup and compilation
            • Components Manual
            • Browser Support
            • Unit Test Manual
            • Development Process
            • Setup AOT/JIT Compilation
          • Decorators
            • Server Event
          • Conventions
            • Application Structure and NgModules
            • Coding
            • Components
            • Data Service
            • Directives
            • Lifecycle hooks
            • Names
            • Services
        • PowerBuilder Kendo Components
          • Base Components
            • base-component
            • column-control
            • controlcontainer
          • Data Manager Componets
            • base-data-manager
            • data-manager-control
            • data-manager-control-base
            • dw-checkbox
            • dw-column
            • dw-complexNumericMaskComponent
            • dw-compute
            • dw-date-time-edit-mask
            • dw-dropdowndatawindow
            • dw-edit
            • dw-edit-mask
            • dw-radio-button
            • dw-simple-numeric-edit-mask
            • dw-string-edit-mask
            • dw-time-edit-mask
          • Window Components
            • basemask
            • graphics
            • w-checkbox
            • w-command-button
            • w-complex-numeric-mask
            • w-date-time-edit-mask
            • w-dropdownlistbox
            • w-group-box
            • w-line
            • w-listbox
            • w-maskedtextbox
            • w-mdiclient
            • w-menu
            • w-multiline
            • w-picture
            • w-picture
            • w-radiobutton
            • w-rectangle
            • w-simple-numeric-edit-mask
            • w-single-line-edit
            • w-statictext
            • w-string-edit-mask
            • w-time-edit-mask
            • w-toolbar
            • w-toolbaritem
            • w-user-object
            • w-window
          • Services
            • DmInteractionService
          • DataManagerEvents
          • FocusManager guide
      • Api Documentation
        • WebMap Silverlight
        • WfNetC1Components
        • WebFormsComponents
      • Guides
        • Setup NPM package registry in the workspace
        • How to Setup WebMap Applications To Run Over SubDomains or WebApplications In IIS
        • Deploy several WebMap Apps in the same Server
        • Update to Angular 16
        • Appearance
          • How to change the CSS
          • How to override the style for a component
        • Component maintenance
          • How link WebMap package to the migrated Application
          • How to resolve broken reference problems with VBUC
          • How to test a local WebMap Components package
          • How to add a new component in a migrated application
          • How to update a component
          • Dynamic Control Support
          • How to add new set of component with a different provider
          • How to test your component in the playground
          • Tools
        • WMLogger
          • How to use the WMLogger's instance
          • How to change log's level
          • How to add log tags
        • Integration test
        • Setup WebMap Applications to Run Front-End And Back-End In Separates Sites
          • Setup WebMap Applications To Run Front-End And Back-End In Separates Sites in Production (IIS)
        • Setup Migrated WebMap Applications To Run Front-end & Back-end In Separates Sites (Only development)
        • Initial Set Up
          • Software to Install
          • Necessary Repositories
      • Errors
      • Version Notes
        • Client Core
        • Angular Client
        • Web Base Components
        • Winforms Angular Components
        • PowerBuilder Kendo Components
      • Licenses
        • Client Core
        • Angular Client
        • Base Components
        • PB Kendo Components
        • WFNet Kendo Components
        • WebForms Components
        • WFNet Access Components
        • WFNet Janus Components
        • WFNet C1 Components
        • Silverlight wms-framework
        • Silverlight i-components
    • BackEnd
      • WebMAP From Scratch
      • Setup
      • DCP: Desktop Compatibly Platform
        • Overview
        • Library Bundles
          • Bundle Library
            • Create an Observable Object
          • Bundle DTO
            • DTO: Data Transfer Objects
              • Creating a DTO
            • Mappers
              • Create Mappers
            • Observable Wrappers
              • Create an Observable Wrapper
            • API/Controllers
      • Architecture
      • Weaving on WebMAP
      • Glossary
      • FAQ
        • How to create a new Control
        • How to create a new Screen
        • What is the Mobilize.WebMAP.CoreServices.All?
        • What is the DesignerAttribute?
        • What is the InterceptedAttribute?
        • What is the Mobilize.Extensions.Logging.RollingFile?
        • What is the ObservableAttribute?
        • What is the Mobilize.Weaving.WebMAPExtensions.All?
      • Licenses
        • PBNet DCP
        • WebFormsDCP
        • WFNet DCP
        • CoreServices
        • CoreServicesCommon
    • Request and Response
  • SCALABILITY
    • Introduction
    • Microservices
    • Containerizing a WebMap .Net Application with Docker
    • Vertical scalability
Powered by GitBook
On this page
  • How does Weaving Work?
  • Creating a new Weaving Extension
  • Analyzer
  • Injector
  • Handling State
  • Accessing the Semantic Model
  • Debuggable Code Generation
  • Useful C# preprocessor directives
  • Code generation best practices

Was this helpful?

  1. General
  2. BackEnd

Weaving on WebMAP

On WebMAP 5, weaving is leveraged to perform some of the changes required so the code can be run on web environments.

By weaving we mean a process that can insert or modify the application code during the compilation process, but in a way that the developers do not have to worry about these modifications, and also in a way that can improve performance, compared with others interception solutions, because it will add little overhead during runtime.

How does Weaving Work?

A program that takes source, and modifies it by inserting aspect-specific logic at joint points. The result are sections of non-visible code in the original code that are executed during runtime.

The point is to keep the modifications required to interact with WebMAP Core Services. To know where and what should we weave into, attributes are used as markers and during the weaving analyzer process the class meta data is recollected and determine the elements that need to be generated.

Creating a new Weaving Extension

A weaving extension is a .NET class library that will be published as a NuGet. It must have a NuGet reference to Mobilize.Weaving, and it will have a structure like:

  • Analyzers

    • Zero or more weaving analyzers

  • build

    • The .props file needed to update the @Plugins property

  • Builders

    • Utility classes for syntax emit

  • Extensions

    • Extensions method to ease some tasks

  • Injectors

    • Zero or more weaving injectors

  • State

    • Classes related to holding state that might be needed or collected by Analyzers or Injectors

Analyzer

An analyzer is a class that inherits from Mobilize.Weaving.Roslyn.Structure.Analyzer where T should be the syntax node that will be inspected. It should override the void Analyze(T node) method and inside this method either the AST will be traversed or the semantical model will be used to track information.

Injector

An injector is a class that inherits from Mobilize.Weaving.Roslyn.Structure.Mutation where T should be a syntax node.

This should override the public override T Apply(T node).

  • If you are not modifying this AST just return the same node parameter.

  • If you want to suppress this node return null.

  • If you want to modify this AST then create a new node and return it.

Data collected from previous Analyzers or the semantic model can be used here. Usually this Injector will use the classes from the Builder folder for common AST construction tasks.

Handling State

To hold state you will create a class that implements the IState interface like the following:

public class SomeState : IState
{
    private Dictionary States { get; set; } = new Dictionary();

    public void Add(SomeData state, string key) => this.States.Add(key, state);
    public bool Contains(string key) => this.States.ContainsKey(key);

    public SomeData Get(string key)
    {
        this.States.TryGetValue(key, out var value);
        return value;
    }
}

The previous example shows a state structure that can be used to map from a class qualified name to some SomeData structure.

To recover this state you can just do something like this:

var state = this.Storage.State();

Accessing the Semantic Model

All analyzers and injectors have access to the semantic model using the Model property:

var semanticModel = this.Storage.State().Model;

Debuggable Code Generation

We need to have some considerations when injecting code in order to maintain the debug experience for the user. When we inject code a new file will be generated. In this new file the injected code will introduce differences from the original file. The user will develop and debug based on the file without injection, but in the background the code that is been executed is specified in the generated file.

Useful C# preprocessor directives

#line

It lets you modify the compiler's line number and (optionally) the file name output for errors and warnings.

  • The #line default directive returns the line numbering to its default numbering, which counts the lines that were renumbered by the previous directive.

  • The #line 200 directive forces the line number to be 200 (although the default is another) and until the next #line directive.

  • The #line 200 "Form1.cs" directive will report the filename as "Form1.cs".

The #line directive might be used in an automated, intermediate step in the build process. For example, if lines were removed from the original source code file, but you still wanted the compiler to generate output based on the original line numbering in the file, you could remove lines and then simulate the original line numbering with #line.

The #line hidden directive hides the successive lines from the debugger, such that when the developer steps through the code, any lines between a #line hidden and the next #line directive (assuming that it is not another #line hidden directive) will be stepped over. This option can also be used to allow ASP.NET to differentiate between user-defined and machine-generated code. Although ASP.NET is the primary consumer of this feature, it is likely that more source generators will make use of it.

A #line hidden directive does not affect file names or line numbers in error reporting. That is, if an error is encountered in a hidden block, the compiler will report the current file name and line number of the error.

The #line filename directive specifies the file name you want to appear in the compiler output. By default, the actual name of the source code file is used. The file name must be in double quotation marks ("") and must be preceded by a line number.

A source code file can have any number of #line directives.

Code generation best practices

In order to provide a correct debugging behavior for the user, we need to follow some practices during the code generation. Basically to specify how the code been executed will match with the code provided by the user in which he will code and debug.

  1. Because new generated code will not have a corresponding code in the original file, we must generate #line hidden or #line default. If we use the #line hidden directive while debugging there will no be any corresponding line in the original, so this generated code will not be reachable for the debugging. If we use the #line default directive the generated code will be reachable. Notice that using the #line default directive will reset the counter to the generated file. So, if it is necessary to reference after that to the original file, the #line filename directive must be used.

  2. After injecting new code is necessary to reestablish the line counter to maintain the debugging experience. That means that if we have added some new code that would be hidden, after it, when it appears code that is also in the original code, we must specify the location of the code through the #line directive.

    Example

        [Intercepted]
        public Mobilize.WebMAP.WinForms.Button button1
#line 72
        {

#line 73
            get
#line hidden
{
    if ((_Mobilize_LoadedFlag_0 & _Mobilize_Loaded_button1) <= 0)
    {
      // Here some generated code
    }

    return this.button1_k__BackingField;
}
#line 73
  1. We must preserve trivias and compensate them with whitespaces according to the original character position to avoid wrong debug highlighting.

Example 1

In the original file:

        public string property1
        {
            get; set;
        }

In the generated file

#line 1
        public
#line 1
               string
#line 1
                       property1
#line 2
        {
#line 3
            get;
#line 3
                 set;
        }

Example 2

In the original file:

        public void Foo()
        {/*
            comments
            which are trailing trivia of
            method body open brace
                    */goo();//Original First statement
        }

In the generated file

        public void Foo()
        {/*
            comments
            which are trailing trivia of
            method body open brace
                    */
#line hidden
        woo();//new generated statement
#line 6
                      goo();//Original First statement
        }
PreviousArchitectureNextGlossary

Last updated 4 years ago

Was this helpful?

Note: Developing Weaving Extensions requires some knowledge of the Roslyn Framework. For more information about Roslyn:

https://github.com/dotnet/roslyn#get-started
#line C# Reference