Reid  Rohan

Reid Rohan

1659460320

Todomvc-imba: Imba TodoMVC Example

Imba • TodoMVC

Create complex web apps with ease! Imba is a new programming language for the web that compiles to highly performant and readable JavaScript. It has language level support for defining, extending, subclassing, instantiating and rendering dom nodes.

Resources

Support

Let us know if you discover anything worth sharing.

Running

  1. Run npm install
  2. Open index.html in your browser to see it in action!

Development

The source resides in src/app.imba. Run npm run watch to recompile the source locally. Make sure you have installed Imba through npm: npm install -g imba first.

Credit

Created by Sindre Aarsaether

Original article source at: https://github.com/somebee/todomvc-imba  

#javascript #todo #mvc 

Todomvc-imba: Imba TodoMVC Example

State Management & Request Package, Model,View,Controller,Request MVCR

mc

MVCRocket State management and request package, Model,View,Controller,Request MVCR.

Author: Mohammed CHAHBOUN

Getting Started

In your flutter project, add the dependency to your pubspec.yaml

dependencies:
  ...
  mc: ^0.0.2

Usage

Simple case use McMV & RocketValue

its very simple

class McMiniViewExample extends StatelessWidget {
  // use mini for convert value to RocketValue
  final RocketValue<String> myStringValue = "My Value".mini;
  final RocketValue<int> myIntValue = 2021.mini;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        //use your value in McMV and if value changed will rebuild widget for show your new value
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // use value for every widget
            McMV(myStringValue, () => Text(myStringValue.v)),
            McMV(myStringValue, () => Text(myIntValue.v.toString())),
            const SizedBox(
              height: 25.0,
            ),
            // merge multi values in one widget
            McMV(RocketValue.merge([myStringValue, myIntValue]), () {
              return Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  Text(myStringValue.v),
                  Text(myIntValue.v.toString())
                ],
              );
            })
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Theme.of(context).primaryColor,
        onPressed: () {
          // change value
          myStringValue.v = "Value Changed";
          myIntValue.v = 2022;
        },
        tooltip: 'change Value',
        child: Icon(Icons.change_circle),
      ),
    );
  }
}

Complex case (state management & request)

firstly you need to create your cket from your json data by this Link you get something like this:

import 'package:mvc_rocket/mvc_rocket.dart';

class Post extends RocketModel<Post> {
  List<Post> multi;
  int userId;
  int id;
  String title;
  String body;

  final String userIdStr = 'userId';
  final String idStr = 'id';
  final String titleStr = 'title';
  final String bodyStr = 'body';

  Post({
    this.userId,
    this.id,
    this.title,
    this.body,
  });

  fromJson(Map<String, dynamic> json) {
    userId = json['userId'] ?? userId;
    id = json['id'] ?? id;
    title = json['title'] ?? title;
    body = json['body'] ?? body;
    return super.fromJson(json);
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['userId'] = this.userId;
    data['id'] = this.id;
    data['title'] = this.title;
    data['body'] = this.body;

    return data;
  }

  void setMulti(List data) {
    List listOfpost = data.map((e) {
      Post post = Post();
      post.fromJson(e);
      return post;
    }).toList();
    multi = listOfpost;
  }
}

Now second step create your RocketRequest in constructor or initState of first widget and pass url & headers

class MyApp extends StatelessWidget {
  MyApp() {
    const String baseUrl = 'https://jsonplaceholder.typicode.com';
    // create request object
    RocketRequest request = RocketRequest(url: baseUrl);
    // save it, for use it from any screen by key
    rocket.add('request', request);    
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
    );
  }
}...

Next step its build [RocketView] Widget & pass your [RocketModel] in [model] & [RocketRequest] method in [call] parameter


class PostExample extends StatelessWidget {
  // Save your model to use on another screen
  // readOnly means if you close and open this screen you will use same data without update it from Api
  // [mc] is instance of Mccontroller injected in Object by extension for use it easily anywhere
  final Post post = McController().add<Post>('posts', Post(), readOnly: true);
  // get request by key
  final RocketRequest request = McController().get<RocketRequest>("request");
  PostExample({this.title});
  final String title;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(
            "Refresh Posts with swip to down or from here =>",
            style: TextStyle(fontSize: 11.0),
          ),
          actions: [
            IconButton(
                icon: Icon(Icons.data_usage),
                // Refresh Data from Api
                onPressed: () => refresh())
          ],
        ),
        body: Container(
          height: MediaQuery.of(context).size.height,
          width: MediaQuery.of(context).size.width,
          child: RefreshIndicator(
              onRefresh: () {
                return refresh();
              },
              child: RocketView(
                // call api method
                // i write post endpoint incorrect for produce an error & use onError builder
                call: () => request.getObjData("posqts", post, multi: true),
                // your model generated
                model: post,
                // handle errors
                onError: (McException exception,Function() reload) {
                  return Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text(exception.exception),
                        Text(exception.response),
                        // reload is method for call api again (call parameter)
                        TextButton(onPressed: reload, child: Text("retry"))
                      ],
                    ),
                  );
                },
                // call api if model is empty & you can choose another ways like default way asFuture(call once) & asStream (call every //[secondsOfStream] seconds)
                callType: CallType.callIfModelEmpty,
                // or
                // callType: CallType.callAsStream,
                // secondsOfStream: 1,
                // customized your loading (default widget is CircularProgressIndicator)
                loader:CustomLoading(),
                builder: (context) {
                  return Container(
                    height: MediaQuery.of(context).size.height * 0.852,
                    child: ListView.builder(
                      itemCount: post.multi.length,
                      itemBuilder: (BuildContext context, int index) {
                        // your data saved in multi list as Post model
                        Post currentPost = post.multi[index];
                        return ListTile(
                            leading: Text(post.id.toString()),
                            title: Text(post.title),
                            onTap: () => Navigator.of(context).push(
                                  MaterialPageRoute(
                                      builder: (BuildContext context) {
                                    return Details(index);
                                  }),
                                ));
                      },
                    ),
                  );
                },
              )),
        ));
  }

  Future<dynamic> refresh() {
    // use http method you want (get,post,put) + ObjData if you used model in RocketView and you can use JsonData for get data directly from api
    return request.getObjData(
    // endpoint
    "posts",
    // your model
    post, 
    // if you received data as List multi will be true & if data as map you not should to define multi its false as default
    multi: true,
    // parameters for send it with request
    params:{"key":"value"},
    // inspect method for determine exact json use for generate your model in first step
    // if your api send data directly without any supplement values you not should define it
    inspect:(data)=>data["response"]
    );
  }
}

& last item its McController for save your model or any value and get it anywhere by key

// inside of object use mc extension 
McController().add("key",value,readOnly:true); // you can't edit it if readonly true
// or
// [add] return value
rocket.add<Type>("key",value);
// [get] return value
rocket.get<Type>("key");
// [remove]
rocket.remove("key");
// remove with condition
rocket.removeWhere((key,value)=>key.contains("ke"));

Graphic tutorial

JPG

More examples

License

MIT License

Copyright (c) 2022 Jahez team

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add mvc_rocket

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  mvc_rocket: ^1.0.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:mvc_rocket/mvc_rocket.dart'; 

example/lib/main.dart

import 'dart:async';
import 'package:example/views/counter_View.dart';
import 'package:example/views/mini_view.dart';
import 'package:example/views/photo_View.dart';
import 'package:example/views/post_View.dart';
import 'package:example/views/user_View.dart';
import 'package:flutter/material.dart';
import 'package:mvc_rocket/mvc_rocket.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        routes: <String, WidgetBuilder>{
          '/miniView': (BuildContext context) => new MiniView(
                title: "MiniView Example",
              ),
          '/counter': (BuildContext context) => new CounterExample(
                title: "Counter",
              ),
          '/user': (BuildContext context) => new UserExample(
                title: "10 Users",
              ),
          '/post': (BuildContext context) => new PostExample(
                title: "100 Posts",
              ),
          '/photo': (BuildContext context) => new PhotoExample(
                title: "5000 Photos",
              ),
        },
        title: '🚀 MVCRocket 🚀 Package',
        theme: ThemeData(
          primaryColor: Colors.brown,
          appBarTheme: AppBarTheme(backgroundColor: Colors.brown),
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: MyApp());
  }
}

// ignore: must_be_immutable
class MyApp extends StatelessWidget {
  final ValueNotifier<double> dx = ValueNotifier<double>(0.1);
  late BuildContext cntx;
  final List<String> exps = [
    "MVCRocket Package",
    "Link your app with API easily",
    "One Package All Features",
    "Make your work easy",
    "this animation make by crazy code with timer"
  ];
  int index = 0;
  MyApp() {
    const String baseUrl = 'https://jsonplaceholder.typicode.com';
    // create request object
    RocketRequest request = RocketRequest(url: baseUrl);
    // save it, for use it from any screen
    rocket.add(mcRequestKey, request);
    Timer.periodic(Duration(milliseconds: 5), (timer) {
      if (dx.value <=
          MediaQuery.of(cntx).size.width +
              (MediaQuery.of(cntx).size.width * 0.04)) {
        dx.value += 0.5;
      } else {
        dx.value = -MediaQuery.of(cntx).size.width;
        if (index < exps.length - 1) {
          index++;
        } else {
          index = 0;
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    cntx = context;
    return Scaffold(
      appBar: AppBar(
        title: Text("🚀 MVCRocket 🚀 PACKAGE"),
        centerTitle: true,
      ),
      body: Center(
        child: Container(
          height: context.height * 0.6,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              ValueListenableBuilder(
                  valueListenable: dx,
                  builder: (context, _, __) {
                    return Transform.translate(
                      offset: Offset(dx.value, 1),
                      //dx: dx.value,
                      child: Text(
                        exps[index],
                        style: Theme.of(context)
                            .textTheme
                            .headline5!
                            .copyWith(fontWeight: FontWeight.bold),
                      ),
                    );
                  }),
              Example("Mini View", "miniView"),
              Example("Counter View", "counter"),
              Example("10 Users", "user"),
              Example("100 Posts", "post"),
              Example("5000 Photos", "photo"),
            ],
          ),
        ),
      ),
    );
  }
}

class Example extends StatelessWidget {
  final String title, to;
  Example(this.title, this.to);
  @override
  Widget build(BuildContext context) {
    return Container(
      width: context.width * 0.6,
      height: context.height * 0.1,
      child: TextButton(
          child: Text(
            title,
            style: TextStyle(
                fontWeight: FontWeight.bold,
                fontSize: 24.0,
                color: Colors.brown),
          ),
          onPressed: () => Navigator.pushNamed(context, "/$to")),
    );
  }
} 

Download Details:

Author: JahezAcademy

Source Code: https://github.com/JahezAcademy/mvc_rocket

#mvc #android #flutter 

State Management & Request Package, Model,View,Controller,Request MVCR
Nat  Grady

Nat Grady

1658677680

Router Solving Electron Hell Callback Passing, Helpfull for MVC

ElectronRouter 

Router solving Electron shell callback passing, helpfull for MVC

Installation

// Install:
npm install electron-router

// Test:
npm test

Motivation

The problem

When making an electron app I usually come down to the same problem: message passing; if you want to send a message to a window you have to keep a reference to it, whatever the module you're sending the message from, which leaves two possible solutions:

  • Pass the wanted window object to every module that needs to send a message to that window.

or

  • Somehow send the message to the owner of the window reference (usually implies callback passing).

On the other hand, when you want to receive a message from the window you have to listen to ipc which is usually great, but forces you to have perfect tune of the variables that the callback is going to access; this does not present a problem by itself, but as the application grows it may become one.

One example of this is when you have a database and want to query it from the window renderer process, either the database is listening on the ipc and aware of the window (keeps a reference to it) for querying/retrieving data or both the window and the database route their data through the main script, becoming some sort of dummy proxy.

After some brainstorming, the solution I came to was designing the Router, it gives similar options to express. I've made a diagram to help visualize all this.

diagram explaining the problem

The solution

The router just triggers the functions you register on by sending events and parameters. Allowing easy message/data passing and respecting the event/callback Electron architecture.

Features

Wildcards

Every sent/listened message can use wildcards

router.on('loading::start', () => { console.log('start loading...') }
router.on('loading::continue', () => { console.log('continue loading...') }
router.on('loading::end', () => { console.log('end loading...') }

...

router.send('loading::start', ...) // logs "start loading"
router.send('loading::*', ...) // logs "start loading", "continue loading", "end loading"

Simple, plain communication

You can send messages unidirectionally from the main process to the renderer process and viceversa (analogous to electron's ipc) (Previous example)

Duplex communication with channels

router.get('config::*')
router.post('config', ( req, res ) => {
    // req.params contain sent parameters
    // res.json sends data back
})
...

router.route('get', 'config::start', ( err, result ) => {
    console.log('got config', result)
})

API

The router is just a static object, there will be one router in the main process and another one on the renderer. Just 'require' it and start listening/sending events/data. What this object does is route callbacks from one side to another passing parameters, triggered by different events. It can listen to ipc events and send window events too. HTTP Verbs are used just as different channels and for completness (equality to express). For every route/event it is possible register wildcard ('*').

You are responsible for unregistering your callbacks with removeListener(listener), or all callbacks with removeAllListeners(), take into account that this will also delete whatever routes where registered on IPC outside the router. In order to do unregister individual callbacks, listeners should not be just anonymous functions.

Instance

// Constructs the object setting its name
let Router = require('electron-router')

// Returns the static instance
let router = Router( name )

Simple communication

// Triggers/Sends a message on the given event name passing provided messages.
router.send( event, msg1, msg2... )

// Register a listener on the given event, triggering the callback when the event is sent.
// Callback receives the messages sent on the other side
router.on( event, ( msg1, msg2... ) => {})

Duplex communication

// Triggers/Sends a message to the given route on the given method (channel, HTTP Verbs)
// passing the given messages to that channel/route handler. 
// Callback is called with err/result when the handler calls res.json()
// if the handler does not call the return function, callback is invoked with Err: Timeout

router.route( method, route, msg1, msg2..., ( err, result ) => {})

// Similar to router.routes.method( route, msg1, msg2..., ( err, result ) => {})

// All handlers on all channels are called with
//     req { parameters: [], method: channel }
//     res { json: [Function] } - function to call with (err, result), triggers the route back

// Registers handler on GET channel at the given route.
router.get( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on POST channel at the given route.
router.post( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on UPDATE channel at the given route.
router.update( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on DELETE channel at the given route.
router.delete( route, ( req, res ) => {}) // must call res.json( err, result )

Examples

// On every module that uses the router
// Import it
let Router = require('electron-router')

// Main script

const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const app = electron.app
const Router = require('electron-router')
let router = Router('MAIN')
let mainWindow = null

...

app.on('ready', () => {

    // Create window
    ... 

  // Setup DB and modules
  ...

    // Do the rest on ready event (triggered from window, which is usaully the slowest component)
    router.on('ready', () => {
        router.on('quit', () => {
            // Close DB
            // Handle quit code
            ...
        })
    })
})

...

// Window script

const $ = require('jquery')
const Router = require('electron-router')
let router = Router('WINDOW')

// On window ready
$(() => {
  // Send ready event to all registered handlers
  router.send('ready')
  ...

  $('#updates').on('click', () => {
      router.route('POST', '/DB', $('#userData').data())
  })
})

...

// DB script

const Router = require('electron-router')
let router = Router('DB')

...

router.on('ready', () => { ... })

// Register trigger for every route on method GET
route.get('*', ( req, res ) => {
    db.find({ id: req.params }, ( err, results ) => {
        res.json( err, results )
    })
})

// Receive data on post method, route /DB
router.post('/DB', ( req, res ) => {
    console.log('Received', req.params)
    // Save data on db
    db.save( req.params, ( err, result ) => {
        // Send save result to the triggerer
        res.json( err, result )
    })
})

Contributing

Any help is welcome, just send a pull request (please document a little what you want to do), with any ideas/code

Future

In the future it could be great to support:

  • MVC frameworks integration (Backbone...) (Should not be too difficult, overwrite sync method on Collections) erbs
  • Template rendering (i.e.: res.render(data))

Notes

The diagram was made with gliffy

Author: Geblanco
Source Code: https://github.com/geblanco/electron-router 
License: MIT license

#electron #router #mvc #passing 

Router Solving Electron Hell Callback Passing, Helpfull for MVC

BlogMVC-CakePHP3: A Simple CakePHP 3 App to See How CakePHP 3 Works!

CakePHP 3 - BlogMVC

A simple CakePHP 3 application to see how CakePHP 3 works !

Installation

  1. Download Composer or update composer self-update.
  2. Run composer install.
  3. Edit config/app.php with your databases informations (Search "Datasources")
  4. RunYou can now either use your machine's webserver to view the default home page, or start up the built-in webserver with:
bin/cake server -p 8765

Then visit http://localhost:8765 to see the welcome page.

bin/cake migrations migrate
bin/cake migrations seed

Author: Kareylo
Source Code: https://github.com/Kareylo/BlogMVC-CakePHP3 
License: 

#php #cakephp #blog #mvc 

BlogMVC-CakePHP3: A Simple CakePHP 3 App to See How CakePHP 3 Works!

A Custom Framework That Works with Flutter

Supplies a custom framework used for more comprehensive and more interactive Web app.

Installing

I don't like the version number suggested in the 'Installing' page. Instead, always go up to the 'major' semantic version number when installing this library package. This means always trailing with two zero, '.0.0'. This allows you to take in any 'minor' versions introducing new features as well as any 'patch' versions that involves bugfixes. Example, to install version 7.9.2, use 7.0.0. Thus, the bug fix, 7.9.2, will be installed the next time you 'upgrade' the dependencies.

  1. patch - bugfixes
  2. minor - Introduced new features
  3. major - Essentially made a new app. It's broken backwards-compatibility and has a completely new user experience. You won't get this version until you increment the major number in the pubspec.yaml file.

And so, in this case, add this to your package's pubspec.yaml file:

dependencies:
   mvc_web: ^1.5.0

What ist it?

This is a custom framework that works like Flutter following an established design pattern and merely brings together all the widgets that makeup Flutter and runs the appropriate ones depending on the parameter values you supply.

It's a framework I use for all my mobile apps, and now, for all my apps on the Web. Let's introduce it to you using the good ol' counter app you're presented with every time you create a new Flutter project. However, this one will be running on a browser with one additional feature: counter app

An App Like Any Other

You can see the counter app example above works with a little Localization as well. Not only can it sense where it is running in the World and use the appropriate localized language---you can change the language with a tap! Thanks to this package called, mvc_web. This example's code accompanies this package, and can be found in this repository.

Further, like any app, a Web app needs to get set up properly before a user can use it. The screenshot below is the main.dart file for the example app. You can see the general theme of the app is set up here. Further, the form of navigation to be used when going from web page to webpage is established here as well as its Localization capabilities. Even the debug flags used during development can be set here in the AppState class constructor displayed below. The AppMVC class is a StatefulWidget, and the AppState class is its State object. Pretty straightforward.

main.dart

You'll find the AppState constructor supplies the developer with a full array of parameter options. All to instruct how the app is to look and behave. If you've gotten to know Flutter, you'll readily recognize the many parameters available to you in the AppState class. It's all to make life a little easier for the humble developer. See below.

You simply have to use the ones you want, and like any good framework, those chosen parameters are then implemented accordingly. Again, this framework works for your mobile apps, but today, we're looking into its Web capabilities.

app_state

Back to the example app, the next two screenshots below focus on the 'home' page---the main webpage for the example app. In the second screenshot, you're introduced to the framework's 'Web Page' widget. It too has its many parameters, but our attention right now is on its controller, CounterAppController. That's where the magic happens in most instances. The 'Web Page' widget extends Flutter's StatefulWidget, and as such it's kept light in code content. As you know, it's traditionally the StatefulWidget's State object and consequently, in this case, the aforementioned Controller that contains the majority of code for a typical Flutter app.

MyApp MyHomePage

The class, CounterAppController, extends the class, WebPageController. It too, as part of the framework, carries a long list of parameter options. See below. On closer inspection, you'll recognize these parameters are traditionally more associated with a Scaffold widget. Again, a custom framework should give ready access to the capabilities of its underlying platform or framework-Flutter in this case.

WebPageController

Now, as you'll see, this particular part of the framework is designed to work with Web apps. And so, further along in the WebPageController class, you have the means to do just that. This is an abstract class, and so to get your Web app up and running, the builder() function is to be implemented. Further along, there are even more functions for your web page. You'll recognize some of the function names listed and so will deduce what they pertain to.

1_dhH7VuGFdUa-AVNdi5ZyiQ

Deeper in this framework, you'll find the anticipated Scaffold widget taking in the many parameter options and supplying default values when none are provided. All so you can build an interactive and comprehensive Web app in Flutter.

scaffold

Again, back to our example app. At first glance, you'll note the ever-important Controller class is using a factory constructor and thus implementing the Singleton design pattern. I find the role of a Controller is best served with a single instance of that class throughout the life of the app. That's because it's called upon to respond to various system and user events throughout the course of its lifecycle and yet is to retain an ongoing and reliable state. A factory constructor readily accomplishes this. Next, note in the screenshot below, an Appbar is defined in the convenient onAppBar() function. However, being such a simple Appbar, it could have just as well been supplied as a parameter to the Controller's constructor. That's demonstrated in the second screenshot below.

CounterAppController CounterAppController

Looking back at the Scaffold widget deep in the framework, it's the AppBar supplied by the parameter that takes precedence. Are you seeing the advantages of using a custom framework yet? Again, you just supply the appropriate parameter values, and the framework worries about the rest. There's no 're-inventing the Wheel' here. It's still using Flutter. It's just worrying about 'how' Flutter is being used for you.

scaffold

And now to the crux of the matter. Inside your Web app's controller, the builder() function is to return a Widget representing a particular web page. It is the equivalent to the build() function in a typical StatefulWidget's State object but this function is privy to a number of operators and to functionality necessary in implementing a web page. You'll note, however, in the screenshot below, you've still access to the same setState() function used in a typical build() function. And so, tapping on the FloatingActionButton will increment that counter as expected. But this time, it's running on a browser.

builder

Now, an alternate approach would be to have the 'interface' (the View) supplied by a separate class in a separate library file altogether. The example app has this also implemented for demonstration purposes in a separate Dart file called, counter_app_view.dart. The previous builder() function is commented out below to make way for this separate class.

Now which approach you use will depend on how 'modular' you wish an app's components to be with high cohesion and low coupling a common desire. In still other instances, it may come down to personal preference---like how one pronounces that fruit many consider a vegetable: "Tomatoes (/təˈmeɪtoʊz/); Tomatoes (/təˈmɑːtoʊz/)."

builder

The CounterApp class now called above is that of typical StatefulWidget. However, the custom framework supplies it with a special State object of the class, StateMVC, so a WebPageController object can then call that State object's setState() function when necessary. In this case, when an incremented counter is to be displayed on the screen. In the screenshot below, the setState() function is called in the Controller: con.onpressed()

In fact, the Controller has access to the State object itself and its other capabilities, but that's for another time. Know now that, since the Controller has a factory constructor, you're only instantiating one instance of this class, that then has access to the appropriate State object you're currently working with: con = CounterAppController(this).

counterApp

A screenshot of that Controller, reveals the setState() function being called in its onPressed() function. Note, there's a separate class being instantiated into a variable called, model, that's responsible for the 'data source' used by this app. Making such separations may be impractical for such a simple app, but is highly recommended as your Flutter apps get more complicated. Clarifying that statement is also for another time, but you likely know what I mean.

controller

Possibly, you're still new to Flutter and may be more comfortable with the traditional approach of calling the setState() function right inside the FloatingActionButton widget. That's easily accomplished as well. See below.

floatingActionButton

Again, these additional capabilities when working with the custom framework's State object will allow your app a little more modular.

mvc_graphic

What's Your Size?

Screen size is important for Flutter Web, and so, the custom framework gives you ready access to the screen size being used when running your app. It's important to know the screen size at any given moment so as to 'draw' the interface accordingly. Things may have to be redrawn, for example, when a mobile phone switches from portrait to landscape.

builder

Usage

Below is the main.dart file for the example app as well as the main Controller involved. The full code is found in the package's /example folder.

import 'package:mvc_web/mvc_web.dart';

import 'package:example/src/controller.dart';

void main() => runApp(MyApp());

class MyApp extends AppMVC {
  MyApp({Key? key}) : super(key: key);

  @override
  AppState createState() => AppState(
        theme: ThemeData(
          // This is the theme of your application.
          primarySwatch: Colors.blue,
        ),
        // This is the app's navigation
        routerDelegate: AppRouterDelegate(routes: {
          '/': (_) => MyHomePage(),
        }),
        // This is the app's localization
        supportedLocales: I10n.supportedLocales,
        localizationsDelegates: [
          I10nDelegate(),
          GlobalWidgetsLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
          GlobalMaterialLocalizations.delegate,
        ],
        // These are flags used during development
//    debugPaintSizeEnabled: true,
        debugShowCheckedModeBanner: false,
      );
}

class MyHomePage extends WebPageWidget {
  MyHomePage({
    Key? key,
  }) : super(
          controller: CounterAppController(),
          key: key,
        );
}
import 'package:mvc_web/mvc_web.dart';

import 'package:example/src/model.dart';

import 'package:example/src/view.dart';

/// The Controller determines the content provided.
class CounterAppController extends WebPageController {
  factory CounterAppController([StateMVC? state]) {
    _this ??= CounterAppController._();
    _this?.addState(state);
    return _this!;
  }
  CounterAppController._()
      : model = CounterAppModel(),
        super(
          appBar: AppBar(
            title: I10n.t('Counter Page Demo'),
            actions: [
              popupMenu(),
            ],
          ),
        );

  static CounterAppController? _this;
  final CounterAppModel model;

  @override
  PreferredSizeWidget? onAppBar() => AppBar(
        title: I10n.t('Counter Page Demo'),
        actions: [
          popupMenu(),
        ],
      );

  /// An example of implementing a separate interface.
  // @override
  // Widget builder(context) => const CounterApp();

  @override
  Widget builder(BuildContext context) {
    final _smallScreen = inSmallScreen;
    final _screenSize = screenSize;
    final _landscape = inLandscape;
    return Column(children: <Widget>[
      SizedBox(height: _screenSize.height * 0.3),
      I10n.t('You have pushed the button this many times:'),
      SizedBox(height: _screenSize.height * 0.05),
      Text(
        '$counter',
        style: Theme.of(context).textTheme.headline4,
      ),
      Container(
        alignment: Alignment.centerRight,
        height: _screenSize.height * 0.1,
        margin: EdgeInsets.fromLTRB(
          _screenSize.width * (_smallScreen ? 0.05 : 0.5),
          _screenSize.height * (_smallScreen ? 0.05 : 0.3),
          _screenSize.width * (_smallScreen ? (_landscape ? 0.05 : 0.05) : 0.3),
          _screenSize.height *
              (_smallScreen ? (_landscape ? 0.05 : 0.05) : 0.05),
        ),
        child: FloatingActionButton(
//          onPressed: onPressed,
          onPressed: () => setState(() {
            incrementCounter();
          }),
          child: const Icon(Icons.add),
        ),
      ),
    ]);
  }

  /// You're free to mimic Flutter's own API
  /// The Controller is able to talk to the View (the State object)
  /// and call the setState() function.
  void onPressed() => setState(() => model.incrementCounter());

  void incrementCounter() => model.incrementCounter();

  int get counter => model.integer;

  final ButtonStyle flatButtonStyle = TextButton.styleFrom(
//    padding: const EdgeInsets.symmetric(horizontal: 16.0),
    shape: const RoundedRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(30)),
    ),
  );
}

Article Link

Read the free Medium article for more info.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add mvc_web

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  mvc_web: ^1.7.0+1

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:mvc_web/mvc_web.dart'; 

example/lib/main.dart

// Copyright 2021 Andrious Solutions Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:mvc_web/mvc_web.dart';

import 'package:example/src/controller.dart';

void main() => runApp(MyApp());

class MyApp extends AppStatefulWidget {
  MyApp({Key? key}) : super(key: key);

  @override
  AppState createAppState() => AppState(
        theme: ThemeData(
          // This is the theme of your application.
          primarySwatch: Colors.blue,
        ),
        // This is the app's navigation
        routerDelegate: AppRouterDelegate(routes: {
          '/': (_) => MyHomePage(),
        }),
        // This is the app's localization
        supportedLocales: AppTrs.supportedLocales,
        localizationsDelegates: [
          L10n.delegate!,
          GlobalWidgetsLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
          GlobalMaterialLocalizations.delegate,
        ],
        // These are flags used during development
//    debugPaintSizeEnabled: true,
        debugShowCheckedModeBanner: false,
      );
}

class MyHomePage extends WebPageWidget {
  MyHomePage({
    Key? key,
  }) : super(
          controller: CounterAppController(),
          key: key ?? GlobalKey(debugLabel: 'mvc_web_example'),
        );
}

Download Details:

Author: AndriousSolutions

Source Code: https://github.com/AndriousSolutions/mvc_web

#flutter #mvc 

A Custom Framework That Works with Flutter
Mike  Kozey

Mike Kozey

1656765970

MVC Design Pattern in Flutter

mvc_pattern

Note, the Framework package, mvc_application, uses mvc_pattern at its core. 

 MVCThe package, mvc_application, allows for easier and, dare I say, faster development and better maintainability. No 're-inventing of the wheel' with already built-in capabilities and features. Accommodating and Intergrated features:

  • Error Handling
  • System Preferences
  • Notifications
  • Date picker
  • App Color picker
  • Dialog Box
  • Customizable Bottom Bar
  • Loading Screen
  • Time Zones
  • Localization

The package, mvc_web, uses mvc_application, but for the Web.

The "Kiss" of Flutter Frameworks

In keeping with the "KISS Principle", this is an attempt to offer the MVC design pattern to Flutter in an intrinsic fashion incorporating much of the Flutter framework itself. All in a standalone Flutter Package.

In truth, this all came about only because I wanted a place to put my 'mutable' code (the business logic for the app) without the compiler complaining about it! Placing such code in a StatefulWidget or a StatelessWidget is discouraged of course--only immutable code should be in those objects. Sure, all that code could go into the State object. That's good since you want access to the State object anyway. After all, it's the main player when it comes to 'State Management' in Flutter. However, it makes for rather big and messy State objects!

Placing the code in separate Dart files would be the solution, but then there would have to be a means to access that ever-important State object. I wanted the separate Dart file or files that had all the functionality and capability of the State object. In other words, that separate Dart file would to have access to a State object!

Now, I had no interest in re-inventing the wheel. I wanted to keep it all Flutter, and so I stopped and looked at Flutter closely to see how to apply some already known design pattern onto it. That's when I saw the State object (its build() function specifically) as 'The View,' and the separate Dart file or files with access to that State object as 'The Controller.'

This package is essentially the result, and it involves just two 'new' classes: StateMVC and ControllerMVC. A StateMVC object is a State object with an explicit life-cycle (Android developers will appreciate that), and a ControllerMVC object can be that separate Dart file with access to the State object (StateMVC in this case). All done with Flutter objects and libraries---no re-inventing here. It looks and tastes like Flutter.

Indeed, it just happens to be named after the 'granddaddy' of design patterns, MVC, but it's actually a bit more like the PAC design pattern. In truth, you could use any other architecture you like with it. By design, you can just use the classes, StateMVC, and ControllerMVC. Heck! You could call objects that extend ControllerMVC, BLoC's for all that matters! Again, all I wanted was some means to bond a State object to separate Dart files containing the 'guts' of the app. I think you'll find it useful.

Installing

I don't always like the version number suggested in the 'Installing' page. Instead, always go up to the 'major' semantic version number when installing my library packages. This means always entering a version number trailing with two zero, '.0.0'. This allows you to take in any 'minor' versions introducing new features as well as any 'patch' versions that involves bugfixes. Semantic version numbers are always in this format: major.minor.patch.

  1. patch - I've made bugfixes
  2. minor - I've introduced new features
  3. major - I've essentially made a new app. It's broken backwards-compatibility and has a completely new user experience. You won't get this version until you increment the major number in the pubspec.yaml file.

And so, in this case, add this to your package's pubspec.yaml file instead:

dependencies:
  mvc_pattern:^8.9.0

Documentation

Turn to this free Medium article for a full overview of the package plus examples: FlutterFramework

Example Code

Copy and paste the code below to get started. Examine the paths specified at the start of every code sequence to determine where these files are to be located.

/// example/lib/main.dart

import 'package:example/src/view.dart';

void main() => runApp(MyApp(key: const Key('MyApp')));
/// example/src/app/view/my_app.dart

import 'package:example/src/view.dart';

import 'package:example/src/controller.dart';

class MyApp extends AppStatefulWidgetMVC {
  const MyApp({Key? key}) : super(key: key);

  /// This is the App's State object
  @override
  AppStateMVC createState() => _MyAppState();
}

class _MyAppState extends AppStateMVC<MyApp> {
  factory _MyAppState() => _this ??= _MyAppState._();
  static _MyAppState? _this;

  @override
  Widget buildApp(BuildContext context) => MaterialApp(
        home: FutureBuilder<bool>(
            future: initAsync(),
            builder: (context, snapshot) {
              //
              if (snapshot.hasData) {
                //
                if (snapshot.data!) {
                  /// Key identifies the widget. New key? New widget!
                  /// Demonstrates how to explicitly 're-create' a State object
                  return MyHomePage(key: UniqueKey());
                } else {
                  //
                  return const Text('Failed to startup');
                }
              } else if (snapshot.hasError) {
                //
                return Text('${snapshot.error}');
              }
              // By default, show a loading spinner.
              return const Center(child: CircularProgressIndicator());
            }),
      );
}
/// example/src/app/controller/app_controller.dart

import 'package:example/src/view.dart';

class AppController extends ControllerMVC with AppControllerMVC {
  factory AppController() => _this ??= AppController._();
  AppController._();
  static AppController? _this;

  /// Initialize any 'time-consuming' operations at the beginning.
  /// Initialize asynchronous items essential to the Mobile Applications.
  /// Typically called within a FutureBuilder() widget.
  @override
  Future<bool> initAsync() async {
    // Simply wait for 10 seconds at startup.
    /// In production, this is where databases are opened, logins attempted, etc.
    return Future.delayed(const Duration(seconds: 10), () {
      return true;
    });
  }

  /// Supply an 'error handler' routine if something goes wrong
  /// in the corresponding initAsync() routine.
  /// Returns true if the error was properly handled.
  @override
  bool onAsyncError(FlutterErrorDetails details) {
    return false;
  }
}
/// example/src/home/view/my_home_page.dart

import 'package:example/src/view.dart';

import 'package:example/src/controller.dart';

/// The Home page
class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, this.title = 'Flutter Demo'}) : super(key: key);

  // Fields in a StatefulWidget should always be "final".
  final String title;

  @override
  State createState() => _MyHomePageState();
}

/// This 'MVC version' is a subclass of the State class.
/// This version is linked to the App's lifecycle using [WidgetsBindingObserver]
class _MyHomePageState extends StateMVC<MyHomePage> {
  /// Let the 'business logic' run in a Controller
  _MyHomePageState() : super(Controller()) {
    /// Acquire a reference to the passed Controller.
    con = controller as Controller;
  }
  late Controller con;

  @override
  void initState() {
    /// Look inside the parent function and see it calls
    /// all it's Controllers if any.
    super.initState();

    /// Retrieve the 'app level' State object
    appState = rootState!;

    /// You're able to retrieve the Controller(s) from other State objects.
    var con = appState.controller;

    con = appState.controllerByType<AppController>();

    con = appState.controllerById(con?.keyId);
  }

  late AppStateMVC appState;

  /// This is 'the View'; the interface of the home page.
  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              /// Display the App's data object if it has something to display
              if (con.dataObject != null && con.dataObject is String)
                Padding(
                  padding: const EdgeInsets.all(30),
                  child: Text(
                    con.dataObject as String,
                    key: const Key('greetings'),
                    style: TextStyle(
                      color: Colors.red,
                      fontSize: Theme.of(context).textTheme.headline4!.fontSize,
                    ),
                  ),
                ),
              Text(
                'You have pushed the button this many times:',
                style: Theme.of(context).textTheme.bodyText2,
              ),
              // Text(
              //   '${con.count}',
              //   style: Theme.of(context).textTheme.headline4,
              // ),
              SetState(
                builder: (context, dataObject) => Text(
                  '${con.count}',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          key: const Key('+'),

          /// Refresh only the Text widget containing the counter.
          onPressed: () => con.incrementCounter(),

          /// The traditional approach calling the State object's setState() function.
          // onPressed: () {
          //   setState(con.incrementCounter);
          // },
          /// You can have the Controller called the interface (the View).
//          onPressed: con.onPressed,
          child: const Icon(Icons.add),
        ),
      );

  /// Supply an error handler for Unit Testing.
  @override
  void onError(FlutterErrorDetails details) {
    /// Error is now handled.
    super.onError(details);
  }
}
/// example/src/home/controller/controller.dart

import 'package:example/src/view.dart';

import 'package:example/src/model.dart';

class Controller extends ControllerMVC {
  factory Controller([StateMVC? state]) => _this ??= Controller._(state);
  Controller._(StateMVC? state)
      : _model = Model(),
        super(state);
  static Controller? _this;

  final Model _model;

  /// Note, the count comes from a separate class, _Model.
  int get count => _model.counter;

  // The Controller knows how to 'talk to' the Model and to the View (interface).
  void incrementCounter() {
    //
    _model.incrementCounter();

    /// Only calls only 'SetState' widgets
    /// or widgets that called the inheritWidget(context) function
    inheritBuild();

    /// Retrieve a particular State object.
    final homeState = stateOf<MyHomePage>();

    /// If working with a particular State object and if divisible by 5
    if (homeState != null && _model.counter % 5 == 0) {
      //
      dataObject = _model.sayHello();
      setState(() {});
    }
  }

  /// Call the State object's setState() function to reflect the change.
  void onPressed() => setState(() => _model.incrementCounter());
}
/// example/src/view.dart

export 'package:flutter/material.dart' hide StateSetter;

export 'package:mvc_pattern/mvc_pattern.dart';

export 'package:example/src/app/view/my_app.dart';

export 'package:example/src/home/view/my_home_page.dart';

export 'package:example/src/home/view/page_01.dart';

export 'package:example/src/home/view/page_02.dart';

export 'package:example/src/home/view/page_03.dart';

export 'package:example/src/home/view/common/build_page.dart';
/// example/src/controller.dart

export 'package:example/src/app/controller/app_controller.dart';

export 'package:example/src/home/controller/controller.dart';

export 'package:example/src/home/controller/another_controller.dart';

export 'package:example/src/home/controller/yet_another_controller.dart';
/// example/src/model.dart

export 'package:example/src/home/model/data_source.dart';

Further information on the MVC package can be found in the article, ‘MVC in Flutter’ online article

Installing

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add mvc_pattern

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  mvc_pattern: ^8.11.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:mvc_pattern/mvc_pattern.dart';

example/lib/main.dart

// Copyright 2022 Andrious Solutions Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:example/src/view.dart';

void main() => runApp(const MyApp(key: Key('MyApp')));

Author: AndriousSolutions
Source Code: https://github.com/AndriousSolutions/mvc_pattern 
License: View license

#flutter #dart #mvc #pattern 

MVC Design Pattern in Flutter

Annotations In Java

How to create Custom Annotations In Java?

https://javatechonline.com/annotations-in-java/ 

#java #javaprogramming #javaprogramminglanguage #javadeveloper #javadevelopment #javadevelopers #javadeveloperjobs #javabackend #javabackenddeveloper #javafullstack #javafullstackdeveloper #javadeveloper #javaprogrammer #javatraining #javaee #j2ee #j2eedeveloper #java8 #microservices #microservicesarchitecture #microservice #microservicios #mvcframework #mvc #collections #sorting #java8 #javacode #spring #springframework #javaspring #javaspringboot #springmvc #springboot #interviewquestions #interviewpreparation #interview #annotation

坂本  健一

坂本 健一

1655982600

.NET Core MVCWebAPIのSwagger

Swagger(OpenAPI)は、RESTAPIを記述するための言語に依存しない仕様です。これにより、コンピューターと人間の両方が、ソースコードに直接アクセスしなくてもRESTAPIの機能を理解できます。Swagger UIは、生成されたOpenAPI仕様を使用して、サービスに関する情報を提供するWebベースのUIを提供します。SwaggerUIはPostmanの代替手段です。

私は自分の記事でSwaggerを数回以上使用しましたが、さまざまなトピックで使用されるマイナーなツールとして使用しました。Swaggerの情報を取得しようとしたとき、これらの記事から検索する必要がありましたが、これは便利ではありませんでした。そこで、これら2つの記事、特にSwagger for .NET MVCWebAPIまたは.NETCoreMVCWebAPIについて書き直しました。

序章

新しい.NETCore5.0 Web APIプロジェクトを作成した場合、WebAPI用のSwaggercientがデフォルトでインストールされます。現在のケースでは、.NET Core 5.0を使用していますが、Web APIはMVCモジュールで作成されているため、Swaggerを手動でインストールする必要があります。この方法は、5.0より前の.NETCoreバージョンで機能します。

この記事は、私の別の記事の一部です 。MVCによるWeb APIの使用.NETCore(1)、サーバー、およびフレームワークでは、Swagger関連の部分がここにあります。そこから詳細を見ることができます。

ステップ1-ASP.NETCoreMVCアプリケーションを作成する

アプリのビルドには、Visual Studio201916.8と.NET5.0SDKのバージョンを使用します。

  1. Visual Studioを起動し、[新しいプロジェクトの作成]を選択します。
  2. [新しいプロジェクトの作成]ダイアログで、[ASP.NETCoreWebアプリケーション]>[次へ]を選択します。
  3. [新しいプロジェクトの構成]ダイアログで、 MVCCallWebAPI プロジェクト名を入力します。
  4. [作成]を選択します。
  5. [新しいASP.NETCoreWebアプリケーションの作成]ダイアログで、[次のコマンドを選択します。
    1. ドロップダウンの.NETCoreおよびASP.NETCore5.0。
    2. ASP.NET Core Webアプリ(Model-View-Controller)。
    3. 作成

アプリをビルドして実行すると、次の画像にアプリが表示されます。

ステップ2〜3-EntityFrameworkを使用したアクションを備えたScaffoldAPIコントローラー

記事「 .NETCore(1)、サーバーおよびフレームワークでMVCによるWebAPIの消費」を参照してください 。

B:最初にEntityFrameworkコードを使用してWebAPIを追加する

  • ステップ1:新しいデータベースコンテキストを設定する
  • ステップ2:EntityFrameworkコードの最初のアプローチを使用してデータベースを操作します。
  • ステップ3、:EntityFrameworkを使用したアクションを備えたScaffoldAPIコントローラー

ステップ4-WebAPI用のSwaggerクライアントを追加する

1.Swaggerクライアントをインストールします

ソリューションエクスプローラー>[NuGetパッケージの管理]でプロジェクトを右クリックし、  Swaggerを検索します

Swashbuckle(Swagger)には3つの主要なコンポーネントがあり、そのうちの2つをインストールするだけで済みます。SwaggerGenとSwaggerUIで、Swaggerが含まれます。

2.startup.cs ファイルにSwaggerクライアントを登録し ます

Startup.ConfigureServices メソッドのサービスコレクションにSwaggerジェネレーターを追加します 。

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // Register the Swagger generator, defining 1 or more Swagger documents
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v2", new OpenApiInfo { Title = "MVCCallWebAPI", Version = "v2" });
    });
    ......
}

Startup.Configure メソッドで、生成されたJSONドキュメントとSwaggerUIを提供するためのミドルウェアを有効にします 。

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Enable middleware to serve generated Swagger as a JSON endpoint.
    app.UseSwagger();

    // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
    // specifying the Swagger JSON endpoint.
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v2/swagger.json", "MVCCallWebAPI");
    });
    ......
}

これで、アプリを実行する準備がほぼ整いました。

ステップ5-アプリを実行してテストする

アプリを実行する前に、ファイルのヘッダーを変更します 。Views/ Shared / _layout.cshtml  Viewsを再度変更して、以下に示すSwagger(11〜13行目)を追加します。

<header>
    <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
        <div class="container">
            <a class="navbar-brand" asp-area="" asp-controller="StoresMVC" asp-action="Index">MVC app</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                    aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                <ul class="navbar-nav flex-grow-1">
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Swagger" asp-action="Index">Web API</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
</header>

次に、アプリを実行します。

Web APIをクリックすると、Swaggerクライアント画面が表示されます。

 

ソース:https ://www.c-sharpcorner.com/article/swagger-for-net-core-mvc-web-api/

#dotnet #netcore #mvc #webapi #swagger 

 .NET Core MVCWebAPIのSwagger

Swagger para .NET Core MVC Web API

Swagger (OpenAPI) é uma especificação independente de linguagem para descrever APIs REST. Ele permite que computadores e humanos entendam os recursos de uma API REST sem acesso direto ao código-fonte. Swagger UI oferece uma UI baseada na web que fornece informações sobre o serviço, usando a especificação OpenAPI gerada. Swagger UI é uma alternativa ao Postman.

Usei o Swagger várias vezes em meus artigos, mas apenas como uma ferramenta menor usada em diferentes tópicos. Quando tentei obter informações do Swagger, tive que pesquisar nesses artigos, que não eram convenientes. Então, reescrevo esses dois artigos, especialmente sobre Swagger para .NET MVC Web API ou .NET Core MVC Web API.

Introdução

Se tivéssemos criado um novo projeto de API Web .NET Core 5.0, o Swagger cient for Web API seria instalado por padrão. Em nosso caso atual, embora usemos o .NET Core 5.0, a API da Web é criada em um módulo MVC, portanto, precisamos instalar o Swagger manualmente. Dessa forma, funcionará para a versão .NET Core anterior à 5.0.

Este artigo é parte do meu outro artigo:  Consumir Web API por MVC No .NET Core (1), Server And Framework , temos aqui a parte relacionada ao Swagger. Você pode ver detalhes de lá.

Etapa 1 - Criar um aplicativo ASP.NET Core MVC

Usamos a versão do Visual Studio 2019 16.8 e .NET 5.0 SDK para compilar o aplicativo.

  1. Inicie o Visual Studio e selecione Criar um novo projeto.
  2. Na caixa de diálogo Criar um novo projeto, selecione Aplicativo Web ASP.NET Core > Avançar.
  3. Na caixa de diálogo Configurar seu novo projeto, insira  MVCCallWebAPI o nome do projeto.
  4. Selecione Criar.
  5. Na caixa de diálogo Criar um novo aplicativo Web ASP.NET Core, selecione,
    1. .NET Core e ASP.NET Core 5.0 nas listas suspensas.
    2. Aplicativo Web ASP.NET Core (Model-View-Controller).
    3. Crio

Compile e execute o aplicativo, você verá a imagem a seguir mostra o aplicativo,

Etapa 2~3 - Controlador de API do Scaffold com Ação usando o Entity Framework

Consulte o artigo  Consume Web API By MVC In .NET Core (1), Server And Framework ,

B: Adicione a API da Web com o código do Entity Framework primeiro

  • Etapa 1: configurar um novo contexto de banco de dados
  • Etapa 2: trabalhar com um banco de dados usando o primeiro aplicativo de código do Entity Framework.
  • Etapa 3,:Scaffold API Controller com Action usando Entity Framework

Etapa 4 - Adicionar cliente Swagger para API da Web

1. Instale o cliente Swagger

Clique com o botão direito do mouse no projeto em Solution Explorer > Manage NuGet Packages, procure  Swagger

Existem três componentes principais para o Swashbuckle (Swagger), precisamos apenas instalar dois deles: SwaggerGen e SwaggerUI, o Swagger seria incluído.

2. Registre o Swagger Client no   arquivo startup.cs

Adicione o gerador Swagger à coleção de serviços no  Startup.ConfigureServices método,

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // Register the Swagger generator, defining 1 or more Swagger documents
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v2", new OpenApiInfo { Title = "MVCCallWebAPI", Version = "v2" });
    });
    ......
}

Habilite o middleware para servir o documento JSON gerado e a UI Swagger, no  Startup.Configure método,

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Enable middleware to serve generated Swagger as a JSON endpoint.
    app.UseSwagger();

    // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
    // specifying the Swagger JSON endpoint.
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v2/swagger.json", "MVCCallWebAPI");
    });
    ......
}

Agora, estamos quase prontos para executar o aplicativo.

Etapa 5 - Executar e testar o aplicativo

Antes de executarmos o aplicativo, modifique o cabeçalho do arquivo:  Views/Shared/_layout.cshtml  Views novamente para adicionar Swagger (linha 11~13), mostrado abaixo,

<header>
    <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
        <div class="container">
            <a class="navbar-brand" asp-area="" asp-controller="StoresMVC" asp-action="Index">MVC app</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                    aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                <ul class="navbar-nav flex-grow-1">
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Swagger" asp-action="Index">Web API</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
</header>

Agora, executamos o aplicativo,

Clique em Web API, temos a tela do Swagger Client,

 

Fonte: https://www.c-sharpcorner.com/article/swagger-for-net-core-mvc-web-api/

#dotnet #netcore #mvc #webapi 

Swagger para .NET Core MVC Web API
Thierry  Perret

Thierry Perret

1655958120

MVC En informatique - Le Modèle MVC

MVC est une abréviation qui signifie Modèle, Vue et Contrôleur. Ce modèle architectural a été créé à la fin des années 1970 pour créer des applications de bureau, mais il est maintenant largement utilisé dans le développement d'applications Web.

Dans cet article, je vais approfondir ce que signifie MVC aux côtés de ses 3 composants, afin que vous puissiez le comprendre.

J'ai également préparé une infographie qui peut vous aider à mieux comprendre MVC, mais vous devez d'abord lire l'article. :)

Ce que nous couvrirons

Qu'est-ce que MVC et pourquoi est-il utilisé ?

En informatique, MVC est un modèle de conception de logiciel permettant d'organiser le code d'application en trois parties entrelacées : un modèle, une vue et un contrôleur.

Le modèle est la logique d'interaction avec la base de données, la vue est l'interface utilisateur avec laquelle l'utilisateur interagit et le contrôleur est l'intermédiaire entre la vue et le modèle.

Dans de nombreux cas, la vue n'interagit jamais directement avec le modèle - le contrôleur remplit cette fonction.

mvc1

Dans certains autres frameworks, le modèle peut interagir directement avec la vue
Copie-de-mvc2

Le modèle de conception MVC vise à diviser le code de l'application en unités qui lui sont propres, de sorte que la maintenance et l'optimisation ne seront pas un problème. C'est ce qu'on appelle communément la "séparation des préoccupations".

Quels langages et frameworks utilisent MVC ?

Dans le passé, MVC était utilisé uniquement pour créer des interfaces graphiques de bureau. Aujourd'hui, de nombreux langages de programmation et frameworks implémentent MVC pour le développement d'applications Web.

Certains frameworks vous obligent même à utiliser MVC, vous avez donc peut-être utilisé MVC sans vous en rendre compte.

Dans une application Express à pile complète, par exemple, les développeurs divisent souvent le code en un dossier de modèle, de contrôleur et de client (vue).
Annotation-2022-06-20-103520

C'est la structure de dossiers d'un générateur de blagues que j'ai construit pour mon footballeur préféré.

Des exemples de langages de programmation qui utilisent MVC sont C, C++, C#, Java, Ruby, Smalltalk et bien d'autres.

Les frameworks qui utilisent MVC sont Angular, Express, Django, Flask, Laravel, Ruby on rails et autres.

Qu'est-ce que le modèle dans MVC ?

Le composant de modèle contient la logique responsable de la récupération des données de la base de données. Pour cela, vous pouvez également utiliser un fichier JSON à la place d'une base de données.

Par exemple, dans la base de données SQL d'une application de commerce électronique, cela pourrait être quelque chose comme product-data = db.get(SELECT * FROM products;).

Dans de nombreux cas, le modèle communique avec le contrôleur pour envoyer des données à la vue (interface utilisateur). Dans d'autres cas, le modèle peut envoyer des données directement à la vue.

Qu'est-ce que la vue dans MVC ?

Le composant de vue est la partie avec laquelle l'utilisateur interagit directement. Il communique avec le contrôleur pour montrer ce que l'utilisateur a demandé avec les actions de la souris et du clavier.

Des langages comme HTML, CSS et JavaScript sont souvent utilisés pour implémenter cette partie. Vous pouvez également utiliser des frameworks tels que React, Vue et Svelte.

Certains développeurs utilisent également des moteurs de modèles tels que Handlebars, ejs et liquidjs pour implémenter la vue.

Dans une application eCormerce, le code pourrait contenir quelque chose comme ceci :

<h1>{{product.name}}</h2>
<ul>
<p>{{product.description}}</p>
<p>{{product.delivery-modes}}</p>

Qu'est-ce que le contrôleur dans MVC ?

Le composant contrôleur est l'intermédiaire entre le modèle et la vue. Ce n'est ni un modèle ni une vue, c'est la partie qui les relie.

Ce que le contrôleur fait avec la vue, c'est recevoir et traiter les demandes et les actions des utilisateurs effectuées avec la vue (interface utilisateur). Ainsi, il traite les requêtes telles que GET, POST, PUTou PATCH, et DELETE.

Lorsque le contrôleur reçoit les demandes de l'utilisateur, il communique ensuite avec le modèle pour obtenir ce que l'utilisateur veut, puis le renvoie à la vue (interface utilisateur) pour que l'utilisateur puisse le voir.

Un pseudocode pour ce que fait le contrôleur se trouve dans l'extrait ci-dessous :

if (success) {
      show products;
} else {
      show error;
}

Conclusion

Le modèle modèle-vue-contrôleur est devenu un modèle d'architecture largement utilisé pour créer des applications Web et d'autres produits logiciels.

Cela peut être déroutant au début, mais un apprentissage et une pratique persistants devraient vous aider à dissiper votre confusion.

Si vous ne savez toujours pas ce qu'est MVC, regardez-le de cette façon :

  • vous appelez un restaurant pour commander une pizza - vous êtes leview
  • vous passez votre commande à un serveur – le serveur est lecontroller
  • le serveur récupère votre pizza au magasin et vous la donne - le magasin est lemodel

Vous pouvez voir que vous, le view, n'avez jamais besoin d'aller au magasin pour votre pizza, tout comme la vue ne récupère jamais les données directement du modèle à de nombreuses reprises.

#mvc 

MVC En informatique - Le Modèle MVC
Lawson  Wehner

Lawson Wehner

1655957460

Strings API Implementation with Communication & Data Container Layers

Wire - communication and data-container layers

Wire - communication and data layers which consist of string keys thus realization of String API when each component of the system - logical or visual - represented as a set of Strings - what it consumes is Data API and what it produces or reacts to is Signals API.

Library aimed to decouple UI from business logic

Schema

It has two layers:

  • Communication Layer (or "bus") consists of "signals" with associated listeners inside specific scope - instances of Wire object. This layer has main API: Wire.add and Wire.send.
  • Data Container Layer - Wire.data, it works as a key-value in-memory map, where value is an instance of WireData object that holds dynamic value and can be subscribed for updates.

WireData also has special implementation for Flutter - WireDataBuilder Widget. This widget makes it possible to reuse business logic in web (with any other UI frameworks like Angular) and in mobile project with Flutter. Take a look at the "example" folder in both repositories (current and wire_flutter) where _shared folder contains reusable code imported in both projects as a dart package (with custom path to package), the folder shared as a separate git branch with git-subrepo

Shared code in Flutter mobile/web and custom HTML dart-web

Also, ported to (Work In Progress):

  • Wire Haxe that can help to compile or better say transpile reusable code in one of the following language: JavaScript, Java, C#, C++, HL, Lua, PHP.

Usage:

Steps from diagram's description above. It's example of counter application (see folder ./example/counter).

Steps: 1, 4, 6 - "box" that processes signals:

class CounterProcessor {
  CounterProcessor() {
    Wire.add(this, CounterSignal.INCREASE, (payload, wireId) {
      Wire.data(CounterDataKeys.COUNT, (value) => (value ?? 0) + 1);
    });
    Wire.add(this, CounterSignal.DECREASE, (payload, wireId) {
      Wire.data(CounterDataKeys.COUNT, (int value) => (value ?? 0) > 0 ? value - 1 : 0);
    });
  }
}

Since there is no Model box in this example, the processor (or controller) updates data by itself the steps 4 and 6 are the part of it.

Steps: 2, 7 - View subscribe to data changes and know how to update itself:

class CounterDisplay extends DomElement {
  CounterDisplay():super(DivElement()) {
    // ... DOM initialization and styling
    final wireData = Wire.data(CounterDataKeys.COUNT);
    wireData.subscribe(update);
    update(wireData.value ?? 0);
  }
  // update or render
  void update(value) { dom.text = value.toString(); }
}

Step: 3 - another View translate UI event to the system signal:

class CounterButton extends DomElement {
  CounterButton(String title, String signal):super(ButtonElement()) {
    // ... DOM initialization and styling
    dom.onClick.listen((_) => Wire.send(signal));
  }
}

Adding wires and WireListeners to the system. In reaction its immediately set new value to data-container layer from function that do decision making Wire.data(CounterDataKeys.COUNT, (oldValue) => newValue).

Steps: 4, 5 - "middleman" who catch all whats happening in the system (in this example it stores counter value to localStorage):

class CounterStorageMiddleware extends WireMiddleware {
  final ls = window.localStorage;

  int getInitialValue() {
    return ls.containsKey(CounterDataKeys.COUNT) ?
      int.parse(ls[CounterDataKeys.COUNT]) : 0;
  }

  @override
  void onData(String key, prevValue, nextValue) {
    print('> CounterMiddleware -> onData: key = ${key} | ${prevValue}-${nextValue}');
    if (key == CounterDataKeys.COUNT) {
      if (nextValue != null) ls[key] = nextValue.toString();
      else { if (ls.containsValue(key)) ls.remove(key); }
    }
  }

  @override void onAdd(Wire wire) { }
  @override void onRemove(String signal, [Object scope, listener]) { }
  @override void onSend(String signal, [data, scope]) { }
}

This "middleman" can be considered as a part of a Model.

Initialization:

void init() {
  final counterStorageMiddleware = CounterStorageMiddleware();
  // Set initial value from local storage
  Wire.data(CounterDataKeys.COUNT, counterStorageMiddleware.getInitialValue());
  // Register middleware after setting initial value to prevent saving initial value
  Wire.middleware(counterStorageMiddleware);
  // Register processor(s) in the system by just creating and instance of it
  processor = CounterProcessor();
  // Create and initialize view parts of the application
  final root = document.querySelector('#root');
  application = ApplicationView(root);
}

That simple!

Preface

Key to a good software product is understanding of how things work together, what do what, software design, separation of concerns and responsibilities, SOLID principles. Here is a good saying from Robert C. Martin:

"Architecture is not about making decisions earlier, but making decisions late. Good architecture is a software structure that allows you to defer critical decisions for as long as possible, defer them to the point where you've got enough information to actually make them, or not make them".

It's always good to protect your business rules from UI changes and make the user interface a plug-in to the business rules, same for domain data make it a plug-in to the business rules and UI.

History

Being in software development over decade now (2020) I have seen many projects built with different tools and technologies, most of them dealt with user interactions and UI layer(s), and I’ve seen, and still see, the same problems everywhere - no strict rules between UI and data, rules are needed to create order, order creates beauty, and beauty survive and thrive. Even if some framework provides these rules and relations between entities they don't have specific tools to force use them, and usually people break them in favor to release feature faster, therefor a software systems could end up in chaos, where business logic mixed with UI and other parts, domain data generate (or resend) from view and coupled with logic of how this data rendered, and other operations that is not related to the view layer (e.g. requests to remote end points). Remember (from Robert C. Martin):

"The only way to go fast, is to go well."

Separation, putting things outside of boundaries, make parts as plugins - that's what I've been thinking about for years, looking at how others work, how things connected, how data propagated through and used in different popular frameworks, in companies custom solutions. And what I realized is that - it all rotated around two concepts:

  1. Data propagation mechanism
  2. Events distribution system

And they both can be represented as an API - Events API and Data API, both could be just a sets of keys without any obligations - set of strings. This idea leads to the concept of layers - two distribution layers one for communication, events or signals, another one for data. That’s how idea of Wire came to life! This way entities expose two parts:

  • what it needs (what data it use or expect to use)
  • what actions it produces (what can be processed)

Component post this information in unique collection of strings - component's Events API and Data API, or it might use general collections shared APIs presented as strings only. Anyway it does not know from where the data come from and who will process actions.

Goal

The aim of this library is to decouple business logic or any logic that makes decisions on data processing, decouple it from UI - this allows to have shared code that can be imported to different projects, with completely different UIs, with any entity.

It's about shared code that can be plug-in or loaded at runtime when it's needed.

General Concepts

A software system consists in leveraging three main concepts:

  1. Data storage and distribution.
  2. Events listening and propagation.
  3. Decision making based on that data (or FSM).

You find these concepts in every program. Basically it's called - Model-View-Controller - meta-pattern or idea of separating program on functional pieces. Understanding MVC is about understanding how programs should work.

Model

Data structure and the ways how to access data define how an application works and how to apply changes. Therefore data definition is the first step in software development. All starts with data. In MVC, the fact that Model is in the first position emphasize it as well. Models in application play a wider role than just value objects definition, it's also a way of how these objects are stored and retrieved, you can think of it as a data API - create, update, delete and etc. Does it make any decisions on how to modify the data? Probably not, maybe only update related data (e.g. in-memory counter of completed todos). And don't forget that there are two types of models - active and passive, one can notify when changes have occurred (active) and another is a plain storage, file or database (passive) - it has to be monitored by a controller or another agent. Next the example of one of TodoModel's methods:

TodoVO create(String text, String note) {
    final todoVO = TodoVO(uuid(), text, note, false);
    final listData = Wire.data(TodoDataParams.LIST);
    final todoList = listData.value as List;
    final count = Wire.data(TodoDataParams.COUNT).value as int;

    todoList.add(todoVO.id);
    Wire.data(todoVO.id, todoVO);
    Wire.data(TodoDataParams.LIST, todoList);
    Wire.data(TodoDataParams.COUNT, count + 1);

    _save();

    print('> TodoModel -> created: ' + todoVO.id + ' - ' + todoVO.text);
    return todoVO;
}

Wire.data('key') plays a role of active model, it holds WireData instances associated with string keys, WireData is a container with data (accessed from .value property) and it can be monitored for updates by subscribing to it - WireData.subscribe((value) => { ... }). To update the value and notify listeners just set the value: Wire.data('key', value). That's simple. It's up to you to decide from where the value (WireData.value) will be updated either from separate entity, a model by calling its data API (together with physical storing in database or sending to a server), or you can do it from controller afterwards when sub-processes will be ended.

View

UI also could have its own state - visual state, and it might not need to be stored in persistent storage at all, only temporarily. Example - accordion’s opened tab, or button hover state, tooltips, input highlight and etc. These states might depend on domain's data and are generated in run-time based on some conditions. Yes, view could have logic inside, but it has to be simple branching conditions and only depends on data passed in, not from multiple data sources, if it is then this is a sign of needed refactoring (for example extracting condition into pre-calculated object property - UserVO.canRoleBeChanged). With Wire view consume data from Data Container Layer - Wire.data(value), then view subscribe to updates and re-render itself when change will happen - WireData.subscribe((value) => { ... }).

class TodoCountView extends DomElement {
  TodoCountView(SpanElement dom):super(dom) {
    var wireData = Wire.data(TodoDataParams.COUNT);
    var update = (value) => dom.innerText = value.toString();
    wireData.subscribe(update);
    update(wireData.value);
  }
}

But not every program has a view, servers might not have UI, and it all depends on the definition of the view. Saying View we mean something that can emit external events about outside world or interaction, and incoming network traffic fit to this definition quite well, and in this case Wire can be a distribution gate for network API calls, just call Wire.send(signal, dto) on network events and every part of internal system can react to it. Wire.send is a Communication Layer - a way to completely separate parts of the application. View sends signals and waits for data to be updated. Other parts of the view can listen for signals as well and update themselves accordingly. Signal is a string type constant and all of them represent Events API of the component or a system.

Controller

Decision making - business logic - the rules, the controller. It's a place where data meet events, their data are mixed with other data, compared and distributed to a model for CRUD operations, then view updates.

We believe and promote the idea that's view is 'just' the UI layer, with the real app being the logic and data kept outside the components tree.

from original article Thoughts on React Hooks, Redux, and Separation of Concerns

Based on this belief we recommend to keep all your business logic, all these data processing and decision making logic outside of a view - in controllers, this is the only right place to do that. Signals listeners placed inside controller. You register a signal by adding it to the Communication Layer with Wire.add(scope, signal, listener). Many signals can be connected to the same listener and vice versa. The listener should follow the specification of WireListener and has two params - data payload it distributes and wire identifier (wid - string constant).

class TodoController {
    TodoModel todoModel;
    TodoController(this.todoModel) {
    
    Wire.add(this, ViewSignals.INPUT, (String data, int wid) {
      var text = data;
      print('> TodoProcessor -> TodoViewOutputSignal.INPUT: ' + text);
      if (text != null && text.isNotEmpty) {
        todoModel.create(text);
        Wire.send(ViewSignals.CLEAR_INPUT);
      }
    });
    
    Wire.add(this, ViewSignals.DELETE, (String data, int wid) {
      var todoId = data;
      print('> TodoProcessor -> TodoViewOutputSignal.DELETE: ' + todoId);
      todoModel.remove(todoId);
    });

    // Or there can be one listener - signal processor
    Wire.add(this, ViewSignals.INPUT,  _signalProcessor);
    Wire.add(this, ViewSignals.EDIT,   _signalProcessor);
    Wire.add(this, ViewSignals.DELETE, _signalProcessor);
    Wire.add(this, ViewSignals.TOGGLE, _signalProcessor);
    // ...
  }

  void _signalProcessor(DTO payload, int wid) {
    var wire = Wire.get(wid: wid).single;
    print('> TodoProcessor -> ${wire.signal}: data = ' + payload.toString());
    // ...
  }
}

In controller you make a decision of how to process input data, do calculation, then data delegated to a model(s), stored or sent to the server, then controller might initiate reaction - send another signal or if data was not updated from model (in Data Container Layer) then controller might update it manually (with Wire.data(key, value)). Application can have multiple controllers each responsible to its particular data processing. You might think of them as reducers from Redux world or commands from PureMVC.

Few words about FLUX

FLUX pattern is a modification of MVC idea, where data flow unidirectional and controllers replaced with so-called "controller-views":

"Views often found at the top of the hierarchy that retrieve data from the stores and pass this data down to their children."

FLUX Diagram

But in general it's all MVC, Wire incorporate these ideas of Flux, but also allows consumers of data additionally react on signals from other parts of the system, basically from anywhere, beside provides a way to manually subscribe to data changes. The basic flow is next:

  1. Consumers request the data and subscribe for its updates - register reactions.
  2. Signals produced somewhere in the system (maybe by the same data consumers) or come from outside (e.g. network requests).
  3. Listeners react to signals and process data coming with them, these listeners are controllers and update data in stores, which then will trigger reactions (also they can send new signals, but its just an options).

Wire in Flutter / WireDataBuilder

Having business logic separated from presentation, events distributed in Communication Layer and data accessible from shared layer (Wire.data) it's now possible to consume the data and send signal from UI easily. In Flutter this means that we can leave visual hierarchy, UI rendering and transitions between screens/pages to the Flutter framework, and consume data in places where it's needed, we can do this with special widget - WireDataBuilder<T>({Key key, String dataKey, Builder builder}) which subscribe with a string dataKey to WireData value and its changes, it rebuilds underlying widget you return from builder function when WireData value updated. However if you need only data in place you still can get it directly with Wire.data('key').value. Here is an example from Todo application: Here is Wire in Flutter

class StatsCounter extends StatelessWidget {
  StatsCounter() : super(key: ArchSampleKeys.statsCounter);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: WireDataBuilder<int>( // <----- Subscribe to update
        dataKey: DataKeys.COUNT, // <------ Data key (string)
        builder: (context, int notCompletedCount) {
          var allTodoCount = Wire.data(DataKeys.LIST).value.length; // <---- Access data without listening for its change
          var numCompleted = allTodoCount - notCompletedCount;
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ...

WIRE API

Wire (static methods):

Wire .add<T>(Object scope, String signal, WireListener<T> listener, [int replies = 0])
bool .send<T>(String signal, {T payload, Object scope}) // Payload or DTO stands for Data Transfer Object
bool .remove(String signal, {Object scope, WireListener listener})
bool .has({String signal, Wire wire})
void .attach(Wire wire)
bool .detach(Wire wire)
bool .purge()
void .middleware(WireMiddleware value)
List<Wire> .get({String signal, Object scope, WireListener listener, int wid})

WireData .data<T>(String key, [T value])

WireListener:

Definition of listener to a signal in Wire.add(scope, signal, listener) To get signal use Wire.get(wid:wid).single

void Function(T payload, int wid)

WireData:

It is a data container that holds dynamic value. WireData can be subscribed (and unsubscribed). It is associated with string key and retrieved from in-memory map with Wire.data(key). WireData can't be null and Wire.data(key) will always return WireData instance, but its initial value can be null (if first call does not have value, e.g.Wire.data(key, null)), to check this initial null value WireData has special property isSet, which is false until not null value won't be set for the first time. To remove value from Data Container Layer use method remove() - it emits null value before remove subscribers and WireData instance, use isSet property to to distinguish between newly created (false) and removed.

WireData subscribe(WireDataListener<T> listener)
WireData unsubscribe(WireDataListener<T> listener)
void refresh()
void remove()
T get value
bool WireData.lock(WireDataLockToken token)
bool WireData.unlock(WireDataLockToken token)
bool get WireData.isLocked

WireDataListener:

Definition of WireData listener in WireData.subscribe(scope, listener)

void Function(T value);

WireMiddleware:

Class that extends WireMiddleware's methods can be added to Wire.middleware(middleware)

abstract class WireMiddleware {
  void onAdd(Wire wire);
  void onSend(String signal, [payload, scope]);
  void onRemove(String signal, [Object scope, WireListener listener]);
  void onData(String param, dynamic prevValue, dynamic nextValue);
}

UML

Generate UML with dcdg (PlantUML): pub global run dcdg -o ./uml/configuration

Examples

1. Counter (web):

  • Open IDEA
  • Select build target - Dart Web, point to example/counter/index.html
  • Run Debug

2. Todo MVC:

2.1 Dart Web and HTML template:

Todo web with Wire

  • Open IDEA
  • Select build target - Dart Web, point to example/todo/index.html
  • Run Debug

2.2 Todo MVC and Flutter:

Todo Flutter with Wire repo

2.1 Todo Angular

Todo Example with AngularDart using shared code

  • Open IDEA
  • Create symlink (or anchor on Windows) from "_shared/todo" folder in "example" folder and put the link in to "todo_angular/lib/src/_shared" folder.
  • Run DartWeb configuration with index.html

3. API calls variations (console):

  • Open IDEA
  • Select build target - Dart Command Line App, point to example/api/wire_api_example.dart
  • Run Debug

Installing

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add wire

With Flutter:

 $ flutter pub add wire

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  wire: ^1.4.7

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:wire/wire.dart';

example/README.md

Examples

For every project in example folder you have to run pub get from terminal or from IDE opened pubspec.yaml

(you might need to change the port number if you want to run multiple web apps simultaneously)

1. Counter (web): Simple "Increase/Decrease/Output" example of Wire use

  • Open IDEA or WebStorm
  • Select build target - Dart Web,
  • Set "HTML file" to: example/counter/index.html
  • Run Debug

2. Todo MVC (web): Complex Todo application based on TodoMVC CSS

Todo with Wire

  • Open IDEA or WebStorm
  • Select build target - Dart Web
  • Path to: example/todo/index.html
  • Run Debug

In case an error like:

Building package executable...
Failed to build webdev:webdev:
../../.pub-cache/hosted/pub.dartlang.org/dds-2.1.6/lib/src/cpu_samples_manager.dart:54:21: Error: Type 'CpuSamplesEvent' not found.
void cacheSamples(CpuSamplesEvent samples) {
^^^^^^^^^^^^^^^
../../.pub-cache/hosted/pub.dartlang.org/dds-2.1.6/lib/src/cpu_samples_manager.dart:54:21: Error: 'CpuSamplesEvent' isn't a type.
void cacheSamples(CpuSamplesEvent samples) {

Edited cpu_samples_manager.dart in ~/.pub-cache/hosted/pub.dartlang.org/dds-2.1.6/lib/src/ and remove type CpuSamplesEvent.

3. API calls variations (console): Possible variation of Wire API use

  • Open IDEA
  • Select build target - Dart Command Line App, point to example/api/wire_api_example.dart
  • Run Debug

4. Todo with AngularDart web

(NO SUPPORT FOR NULL-SAFETY - DEPRECATED)

Todo with Wire

  • Open folder from IDEA
  • Create symlink (or anchor on Windows) from "_shared" folder in "example" folder and put the link in to "todo_angular/lib/src/" folder.
  • Run DartWeb configuration with index.html

Setup in IDEA:

To run these examples import them as a module from File -> Project Structure in IDEA and enable Dart SDK for each from Preferences -> Languages & Frameworks -> Dart

Import as module Import as module

Author: WiresWare
Source Code: https://github.com/WiresWare/wire_dart 
License: View license

#flutter #dart #mvc #layers 

Strings API Implementation with Communication & Data Container Layers
Léon  Peltier

Léon Peltier

1655908335

Swagger Personnalisé Pour l'API Web REST

Swagger (OpenAPI) est une spécification indépendante du langage pour décrire les API REST. Il permet aux ordinateurs et aux humains de comprendre les capacités d'une API REST sans accès direct au code source. Swagger UI propose une interface utilisateur Web qui fournit des informations sur le service, à l'aide de la spécification OpenAPI générée. Swagger UI est une alternative à Postman.

Nous réalisons cet article dans le groupe de Swagger :relié :

Introduction

Avec l'API Web REST, nous utilisons un verbe pour définir le comportement,

tandis que l'URI (nom) pour identifier une ressource. Cependant, parfois, les combinaisons de verbes et de noms ne suffisent pas à décrire les fonctionnalités de l'API Web. Par conséquent, plus d'explications pourraient être nécessaires pour le client REST. Cet article explique comment ajouter des commentaires C # dans Swagger.

Voici le contenu de l'article :

  • Introduction
  • A - Commentaires de documentation XML (Guide de programmation C#)
  • B - 1 : Écrire des commentaires spéciaux dans un fichier XML par .NET
  • B - 2 : Rédigez des commentaires spéciaux dans les notes Swagger par .NET
  • C - 1 : Écrire des commentaires spéciaux dans un fichier XML par .NET Core
  • C - 2 : Rédiger des commentaires spéciaux dans les notes Swagger .NET Core

A - Commentaires de documentation XML (Guide de programmation C#)

Forme spéciale des commentaires C#

Les commentaires ayant une certaine forme (spéciale) peuvent être utilisés pour ordonner à un outil de produire du XML à partir de ces commentaires et des éléments de code source qu'ils précèdent. Ces commentaires sont les  Single-Line_Comment s ( §6.3.3 ) qui commencent par trois barres obliques ( ///), ou  Delimited_Comment s ( §6.3.3 ) qui commencent par une barre oblique et deux astérisques ( /**). 

Single_Line_Doc_Comment
    : '///' Input_Character*
    ;

Delimited_Doc_Comment
    : '/**' Delimited_Comment_Section* ASTERISK+ '/'
    ;

L'emplacement des commentaires spéciaux

Ils doivent précéder immédiatement un type défini par l'utilisateur ou un membre qu'ils annotent. Les sections d'attribut ( §21.3 ) sont considérées comme faisant partie des déclarations, donc les commentaires de documentation doivent précéder les attributs appliqués à un type ou un membre. Par exemple:

/// <summary>
///  This class performs an important function.
/// </summary>
public class MyClass{}

Écrivez des commentaires spéciaux dans un fichier XML par commande :

Lorsque vous compilez avec  /doc  , le compilateur recherche toutes les balises XML dans le code source et crée un fichier de documentation XML. 

Vous pouvez voir un exemple de page de  Comment : utiliser les fonctionnalités de documentation XML (Guide de programmation C#) | Microsoft Docs .

Dans du code,

Dans le fichier XML de sortie,

<member name="T:SomeClass">
    <summary> Class level summary documentation goes here.</summary>
        <remarks> Longer comments can be associated with a type or member through the remarks tag</remarks>
    </member>
<member name="F:SomeClass.m_Name">

B - 1 : Ecrire des commentaires spéciaux dans un fichier XML par .NET :

Écrivez des commentaires spéciaux dans l'API Web :

Code source:

Créez le fichier XML en tant que sortie :  --- équivalent à l'utilisation de l'  option /doc  comipling en ligne de commande :

Cliquez avec le bouton droit sur le projet ==> Propriétés ==> Construire ==> sortie ==> Vérifier le fichier de document XML avec le chemin

Le fichier XML de sortie :  --- À l'emplacement bin\WebBlogApi.xml

B - 2 : Rédigez des commentaires spéciaux dans les notes Swagger par .NET

Cette forme originale fanfaronne, même si nous pouvons utiliser le verbe REST et le nom de l'API Web (nom) pour distinguer l'entité et l'anctionnalité, parfois il n'y en a toujours pas assez. Désormais, les commentaires spéciaux C # joueront un rôle.

Configurer Swagger

Une fois que nous avons le fichier XML avec les commentaires spéciaux C#, nous pouvons exporter les informations dans Swagger, en configurant Swagger :

Swagger avec commentaires spéciaux Remarques :

C - 1 : Écrire des commentaires spéciaux dans un fichier XML par .NET Core

Créez le fichier XML en tant que sortie :  --- équivalent à l'utilisation de l'  option /doc  comipling en ligne de commande :

Cliquez avec le bouton droit sur le projet ==> Propriétés ==> Construire ==> sortie ==> Vérifiez le fichier de document XML avec le chemin, c'est Visual Studio 2022 :

Le fichier XML de sortie :  --- par défaut, accédez à l'emplacement bin\Debug\net5.0\WebBlogApi.xml

C - 2 : Rédiger des commentaires spéciaux dans les notes Swagger .NET Core

Ceci est pour .Net Core, sortie d'origine

Configurer Swagger

Swagger avec des notes de commentaires spéciaux

Référence

Source : https://www.c-sharpcorner.com/article/customized-swagger-for-net-mvc-web-api/

#dotnet #netcore #mvc #webapi #swagger 

Swagger Personnalisé Pour l'API Web REST

Swagger Personalizado para API web REST

Swagger (OpenAPI) es una especificación independiente del idioma para describir las API REST. Permite que tanto las computadoras como los humanos comprendan las capacidades de una API REST sin acceso directo al código fuente. La interfaz de usuario de Swagger ofrece una interfaz de usuario basada en web que proporciona información sobre el servicio mediante la especificación OpenAPI generada. Swagger UI es una alternativa a Postman.

Realizamos este artículo en el grupo de Swagger:relacionado:

Introducción

Con REST Web API, usamos verbo para definir el comportamiento,

mientras que el URI (sustantivo) para identificar un recurso. Sin embargo, a veces, las combinaciones de verbos y sustantivos aún no son suficientes para describir las funciones de la API web. Por lo tanto, es posible que se necesiten más explicaciones para el cliente REST. Este artículo discutirá cómo agregar comentarios de C# en Swagger.

Este es el contenido del artículo:

  • Introducción
  • A - Comentarios de la documentación XML (Guía de programación de C#)
  • B - 1: escribir comentarios especiales en un archivo XML mediante .NET
  • B - 2: Escribir comentarios especiales en notas Swagger por .NET
  • C - 1: escribir comentarios especiales en un archivo XML mediante .NET Core
  • C - 2: escribir comentarios especiales en las notas de Swagger .NET Core

A - Comentarios de la documentación XML (Guía de programación de C#)

Forma especial de comentarios de C#

Los comentarios que tienen una cierta forma (especial) se pueden usar para dirigir una herramienta para producir XML a partir de esos comentarios y los elementos del código fuente que preceden. Dichos comentarios son  Single-Line_Comment s ( §6.3.3 ) que comienzan con tres barras inclinadas ( ///), o  Delimited_Comment s ( §6.3.3 ) que comienzan con una barra inclinada y dos asteriscos ( ). /**

Single_Line_Doc_Comment
    : '///' Input_Character*
    ;

Delimited_Doc_Comment
    : '/**' Delimited_Comment_Section* ASTERISK+ '/'
    ;

La ubicación de los comentarios especiales

Deben preceder inmediatamente a un tipo definido por el usuario o un miembro que anotan. Las secciones de atributos ( §21.3 ) se consideran parte de las declaraciones, por lo que los comentarios de la documentación deben preceder a los atributos aplicados a un tipo o miembro. Por ejemplo:

/// <summary>
///  This class performs an important function.
/// </summary>
public class MyClass{}

Escriba comentarios especiales en un archivo XML mediante el comando:

Cuando compila con  /doc,  el compilador buscará todas las etiquetas XML en el código fuente y creará un archivo de documentación XML. 

Puede ver una página de muestra de  Cómo: Usar las funciones de documentación XML (Guía de programación de C#) | Documentos de Microsoft .

En codigo,

En el archivo XML de salida,

<member name="T:SomeClass">
    <summary> Class level summary documentation goes here.</summary>
        <remarks> Longer comments can be associated with a type or member through the remarks tag</remarks>
    </member>
<member name="F:SomeClass.m_Name">

B - 1: Escribir comentarios especiales en un archivo XML por .NET:

Escriba comentarios especiales en la API web:

Código fuente:

Cree el archivo XML como una salida:  --- equivalente a usar la  opción /doc  para compilar en la línea de comandos:

Haga clic con el botón derecho en el proyecto ==> Propiedades ==> Generar ==> salida ==> Verifique el archivo del documento XML con la ruta

El archivo XML de salida:  --- En la ubicación en bin\WebBlogApi.xml

B - 2: Escribir comentarios especiales en notas Swagger por .NET

Esta forma original de fanfarronería, incluso podemos usar el verbo REST y el nombre de la API web (sustantivo) para distinguir la entidad y la funcionalidad, en algún momento todavía no hay suficientes. Ahora, los comentarios especiales de C# desempeñarán un papel.

Configurar Swagger

Una vez que tengamos el archivo XML con los comentarios especiales de C#, podemos exportar la información a Swagger configurando Swagger:

Swagger con comentarios especiales Notas:

C - 1: escribir comentarios especiales en un archivo XML mediante .NET Core

Cree el archivo XML como una salida:  --- equivalente a usar la  opción /doc  para compilar en la línea de comandos:

Haga clic derecho en el Proyecto ==> Propiedades ==> Generar ==> salida ==> Verifique el archivo del documento XML con la ruta, este es Visual Studio 2022:

El archivo XML de salida:  --- por defecto ir a la ubicación en bin\Debug\net5.0\WebBlogApi.xml

C - 2: escribir comentarios especiales en las notas de Swagger .NET Core

Esto es para .Net Core, salida original

Configurar Swagger

Swagger con notas de comentarios especiales

Referencia

Fuente: https://www.c-sharpcorner.com/article/customized-swagger-for-net-mvc-web-api/

#dotnet #netcore #mvc #webapi #swagger 

Swagger Personalizado para API web REST
顾 静

顾 静

1655907744

为 REST Web API 定制的 Swagger

Swagger (OpenAPI) 是一种与语言无关的规范,用于描述 REST API。它允许计算机和人类在不直接访问源代码的情况下理解 REST API 的功能。Swagger UI 提供了一个基于 Web 的 UI,它使用生成的 OpenAPI 规范提供有关服务的信息。Swagger UI 是 Postman 的替代品。

我们在 Swagger:related 组中制作这篇文章:

介绍

使用 REST Web API,我们使用动词来定义行为,

而URI(名词)来标识一个资源。但是,有时动词和名词的组合还不足以描述 Web API 的特性。因此,REST 客户端可能需要更多解释。本文将讨论如何在 Swagger 中添加 C# 注释。

这是文章的内容:

  • 介绍
  • A - XML 文档注释(C# 编程指南)
  • B - 1:通过 .NET 将特殊注释写入 XML 文件
  • B - 2:通过 .NET 在 Swagger 笔记中写入特殊注释
  • C - 1:通过 .NET Core 将特殊注释写入 XML 文件
  • C - 2:在 Swagger 笔记 .NET Core 中写入特殊注释

A - XML 文档注释(C# 编程指南)

C# 注释的特殊形式

具有某种(特殊)形式的注释可用于指导工具从这些注释和它们之前的源代码元素生成 XML。此类注释是以 三个斜杠 ( ) 开头的Single-Line_Comment ( §6.3.3/// ) ,或 以斜杠和两个星号 () 开头的Delimited_Comment ( §6.3.3/** )。 

Single_Line_Doc_Comment
    : '///' Input_Character*
    ;

Delimited_Doc_Comment
    : '/**' Delimited_Comment_Section* ASTERISK+ '/'
    ;

特别评论的位置

它们必须紧跟在用户定义类型或它们注释的成员之前。属性部分(第21.3节)被视为声明的一部分,因此文档注释必须在应用于类型或成员的属性之前。例如:

/// <summary>
///  This class performs an important function.
/// </summary>
public class MyClass{}

通过命令将特殊注释写入 XML 文件:

当您使用 /doc 编译时,编译器将搜索源代码中的所有 XML 标记并创建一个 XML 文档文件。 

您可能会看到 如何:使用 XML 文档功能(C# 编程指南)| 中的示例页面。微软文档

在代码中,

在输出 XML 文件中,

<member name="T:SomeClass">
    <summary> Class level summary documentation goes here.</summary>
        <remarks> Longer comments can be associated with a type or member through the remarks tag</remarks>
    </member>
<member name="F:SomeClass.m_Name">

B - 1:通过 .NET 将特殊注释写入 XML 文件:

将特殊注释写入 Web API:

源代码:

将 XML 文件作为输出:  --- 相当于在命令行中使用 /doc 选项编译:

右键单击项目 ==> 属性 ==> 构建 ==> 输出 ==> 使用路径检查 XML 文档文件

输出 XML 文件:  --- 在 bin\WebBlogApi.xml 的位置

B - 2:通过 .NET 在 Swagger 笔记中写入特殊注释

这种大摇大摆的原始形式,即使我们可以使用 REST 动词和 Web API 名称(名词)来区分实体和动作,有时仍然不够。现在,C# 特别注释将发挥作用。

配置 Swagger

在我们拥有包含 C# 特殊注释的 XML 文件后,我们可以通过配置 Swagger 将信息导出到 Swagger 中:

大摇大摆的特别评论注意事项:

C - 1:通过 .NET Core 将特殊注释写入 XML 文件

将 XML 文件作为输出:  --- 相当于在命令行中使用 /doc 选项编译:

右键单击项目 ==> 属性 ==> 构建 ==> 输出 ==> 使用路径检查 XML 文档文件,这是 Visual Studio 2022:

输出 XML 文件:  --- 默认转到 bin\Debug\net5.0\WebBlogApi.xml 的位置

C - 2:在 Swagger 笔记 .NET Core 中写入特殊注释

这是.Net Core,原始输出

配置 Swagger

带有特殊评论的大摇大摆

参考

来源:https ://www.c-sharpcorner.com/article/customized-swagger-for-net-mvc-web-api/

#dotnet #netcore #mvc #webapi #swagger 

为 REST Web API 定制的 Swagger
Trung  Nguyen

Trung Nguyen

1655906880

Swagger Tùy Chỉnh cho REST Web API

Swagger (OpenAPI) là một đặc tả ngôn ngữ bất khả tri để mô tả các API REST. Nó cho phép cả máy tính và con người hiểu được các khả năng của REST API mà không cần truy cập trực tiếp vào mã nguồn. Giao diện người dùng Swagger cung cấp giao diện người dùng dựa trên web cung cấp thông tin về dịch vụ, sử dụng đặc tả OpenAPI đã tạo. Swagger UI là một lựa chọn thay thế cho Postman.

Chúng tôi thực hiện bài viết này trong nhóm của Swagger: liên quan:

Giới thiệu

Với REST Web API, chúng tôi sử dụng động từ để xác định hành vi,

trong khi URI (danh từ) để xác định một tài nguyên. Tuy nhiên, đôi khi, sự kết hợp động từ và danh từ không đủ để mô tả các tính năng của Web API. Do đó, có thể cần nhiều giải thích hơn cho ứng dụng khách REST. Bài viết này sẽ thảo luận về cách thêm bình luận C # vào Swagger.

Đây là nội dung của bài viết:

  • Giới thiệu
  • A - Nhận xét về Tài liệu XML (Hướng dẫn Lập trình C #)
  • B - 1: Viết Nhận xét Đặc biệt vào tệp XML bằng .NET
  • B - 2: Viết Nhận xét đặc biệt vào ghi chú Swagger bằng .NET
  • C - 1: Viết Nhận xét Đặc biệt vào tệp XML bằng .NET Core
  • C - 2: Viết Nhận xét đặc biệt vào ghi chú Swagger .NET Core

A - Nhận xét về Tài liệu XML (Hướng dẫn Lập trình C #)

Dạng đặc biệt của C # Comments

Các chú thích có một dạng (đặc biệt) nhất định có thể được sử dụng để chỉ đạo một công cụ tạo ra XML từ các chú thích đó và các phần tử mã nguồn mà chúng đứng trước. Các nhận xét như vậy là  Single-Line_Comment s ( §6.3.3 ) bắt đầu bằng ba dấu gạch chéo ( ///), hoặc  Delimited_Comment s ( §6.3.3 ) bắt đầu bằng dấu gạch chéo và hai dấu hoa thị ( /**). 

Single_Line_Doc_Comment
    : '///' Input_Character*
    ;

Delimited_Doc_Comment
    : '/**' Delimited_Comment_Section* ASTERISK+ '/'
    ;

Vị trí của các bình luận đặc biệt

Họ phải đặt ngay trước kiểu do người dùng xác định hoặc thành viên mà họ chú thích. Các phần thuộc tính ( §21.3 ) được coi là một phần của khai báo, vì vậy các chú thích về tài liệu phải đặt trước các thuộc tính được áp dụng cho một kiểu hoặc thành viên. Ví dụ:

/// <summary>
///  This class performs an important function.
/// </summary>
public class MyClass{}

Viết Nhận xét Đặc biệt vào tệp XML bằng Lệnh:

Khi bạn biên dịch với  / doc  , trình biên dịch sẽ tìm kiếm tất cả các thẻ XML trong mã nguồn và tạo một tệp tài liệu XML. 

Bạn có thể thấy một trang mẫu từ  Cách: Sử dụng các Tính năng của Tài liệu XML (Hướng dẫn Lập trình C #) | Tài liệu Microsoft .

Trong mã,

Trong tệp XML đầu ra,

<member name="T:SomeClass">
    <summary> Class level summary documentation goes here.</summary>
        <remarks> Longer comments can be associated with a type or member through the remarks tag</remarks>
    </member>
<member name="F:SomeClass.m_Name">

B - 1: Viết Nhận xét Đặc biệt vào tệp XML bằng .NET:

Viết Nhận xét Đặc biệt vào API Web:

Mã nguồn:

Tạo tệp XML làm đầu ra:  --- tương đương với việc sử dụng  tùy chọn / doc  comipling trong dòng lệnh:

Nhấp chuột phải vào Dự án ==> Thuộc tính ==> Xây dựng ==> đầu ra ==> Kiểm tra tệp tài liệu XML với đường dẫn

Tệp XML đầu ra:  --- Ở vị trí tại bin \ WebBlogApi.xml

B - 2: Viết Nhận xét đặc biệt vào ghi chú Swagger bằng .NET

Hình thức ban đầu vênh váo này, thậm chí chúng ta có thể sử dụng động từ REST và tên Web API (danh từ) để phân biệt thực thể và tính định hướng, đôi khi vẫn chưa đủ. Bây giờ, các Nhận xét Đặc biệt của C # sẽ đóng một vai trò.

Định cấu hình Swagger

Sau khi chúng tôi có tệp XML với C # Special Comments, chúng tôi có thể nhập thông tin vào Swagger, bằng cách định cấu hình Swagger:

Swagger với Ghi chú Nhận xét Đặc biệt:

C - 1: Viết Nhận xét Đặc biệt vào tệp XML bằng .NET Core

Tạo tệp XML làm đầu ra:  --- tương đương với việc sử dụng  tùy chọn / doc  comipling trong dòng lệnh:

Nhấp chuột phải vào Dự án ==> Thuộc tính ==> Xây dựng ==> xuất ==> Kiểm tra tệp tài liệu XML với đường dẫn, đây là Visual Studio 2022:

Tệp XML đầu ra:  --- theo mặc định đi đến vị trí tại bin \ Debug \ net5.0 \ WebBlogApi.xml

C - 2: Viết Nhận xét đặc biệt vào ghi chú Swagger .NET Core

Đây là cho .Net Core, đầu ra gốc

Định cấu hình Swagger

Swagger với ghi chú nhận xét đặc biệt

Tài liệu tham khảo

Nguồn: https://www.c-sharpcorner.com/article/customized-swagger-for-net-mvc-web-api/

#dotnet #netcore #mvc #webapi #swagger 

Swagger Tùy Chỉnh cho REST Web API