Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
May 5, 2021 08:19 pm GMT

How can we integrate FLutter with .Net core web API | Flutter Bloc State Management.

In this article, We are going to build together. A flutter mobile application.that looks like the following.
This is the main page of the application that will display the services lists that exists in one category.

Alt Text

and this is the service add page.

Alt Text

and this one is the service detail page on this page we can delete and edit the single service.

Alt Text

This app will list the services that came from the back-end server which is the .net web API, then it will create a new service at the back-end, it can also display the service detail on the page, and on that page, we can edit and delete the service.

so here we will follow some steps to do this application.

Pre requests

1.Installing Android studio
2.Installing Flutter and dart

Step 1: Creating a new Flutter Project from an android studio or visual studio code.

image

Then you will get the following page.
Click on the Flutter Application and click on the Next button

image
then here give the application a new name.and click on the next button.

image
Then click on the Finish button at the bottom.
image

here we get a default code.

image

first, we should prepare a debugging emulator or connect our phone. and it will come at the top, after that click on the green run button at the top. you will get this page on the emulator.

Alt Text

leave this code, for now, we will update it later.
now create a new directory called Service inside the lib package and inside this directory create the following directories.

image

Let us see step by step the code insides these directories.

Bloc

Create the following dart files inside the Bloc directory.

image

What is Bloc State Management?

Bloc Overview

Overall, Bloc attempts to make state changes predictable by regulating when a state change can occur and enforcing a single way to change state throughout an entire application.

Below are common developer needs that Bloc tries to address

  • Working as efficiently as possible and reuse components both within your application and across other applications.
  • Letting many developers to seamlessly work within a single code base
  • following the same patterns and conventions Developing fast and reactive apps
  • knowing what state your application is in at any point in time
  • Easily testing every case to make sure our app is respondingappropriately
  • Recording every single user interaction in your application so that you can make data-driven decisions

Installing and Importing Bloc package

Installation
Add the flutter_bloc package to your pubspec.yaml as a dependency

dependencies:
flutter_bloc: ^6.1.1

Import
import 'package:flutter_bloc/flutter_bloc.dart';

Bloc Architecture

image

Bloc Architecture: Data Layer

The data layer's responsibility is to retrieve/manipulate data from one or more sources The data layer can be split into two parts
Repository
Data Provider
This layer is the lowest level of the application and interacts with databases, network requests, and other asynchronous data sources

Bloc Architecture: Data Layer -> Data Provider

The data provider's responsibility is to provide raw data.It should be generic and versatile and it will usually expose simple APIs to perform CRUD operations. We might have a createData, readData, updateData, and deleteData method as part of our data layer.

Inside the DataProvider directory create the following two dart files.

image

Service_data.dart

then inside the Service_data.dart file first add the necessary imports.

import 'dart:convert';import 'package:flutter/cupertino.dart';import 'package:flutter_group_project/Service/Model/Service.dart';import 'package:meta/meta.dart';import 'package:http/http.dart' as HTTP;

create a class called ServiceDataProvider

class ServiceDataProvider {}

then inside this class first define the Url for which it will fetch the data from the back-end API

final _baseUrl = 'http://192.168.42.232:5000/api';

Then define the httpClient

final http.Client httpClient;

next, add the constructor for the class.

ServiceDataProvider({@required this.httpClient}) : assert(httpClient != null);

after this let't us add the code for the create method. this method will communicate with the back-end inorder to create the data at the back-end database.

    Future<Service> createService(Service service) async {    final response = await httpClient.post(      Uri.http('http://192.168.42.232:5000', '/api/services'),      headers: <String, String>{        'Content-Type': 'application/json; charset=UTF-8',      },      body: jsonEncode(<String, dynamic>{        "serviceName": service.ServiceName,        "description": service.Description,        "category": service.Category,        "initialPrice": service.InitialPrice,        "intermediatePrice":service.IntermediatePrice,        "advancedPrice":service.AdvancedPrice,      }),    );    if (response.statusCode == 200) {      return Service.fromJson(jsonDecode(response.body));    } else {      throw Exception('Failed to create course.');    }  }

This is the get method.

Future<List<Service>> getServices() async {    try{     final response = await http.get('${_baseUrl}/services');     if (response.statusCode == 200) {       final services = jsonDecode(response.body) as List;       return services.map((service) => Service.fromJson(service)).toList();     } else {       throw Exception('Failed to load courses');     }   }catch(e){     print("Exception throuwn $e");    }  }

This one is the delete method.

Future<void> deleteService(int  id) async {    final http.Response response = await http.delete(      'http://192.168.43.163:5000/Service/$id',      headers: <String, String>{        'Content-Type': 'application/json; charset=UTF-8',      },    );    if (response.statusCode != 200) {      throw Exception('Failed to delete course.');    }  }

and this one is the update method.

Future<void> updateService(Service service) async {    final http.Response response = await httpClient.put(      'http://192.168.43.163:5000/Service/',      headers: <String, String>{        'Content-Type': 'application/json; charset=UTF-8',      },      body: jsonEncode(<String, dynamic>{        "serviceId":service.id,        "serviceName": service.ServiceName,        "description": service.Description,        "category": service.Category,        "initialPrice": service.InitialPrice,        "intermediatePrice":service.IntermediatePrice,        "advancedPrice":service.AdvancedPrice,      }),    );    if (response.statusCode != 200) {      throw Exception('Failed to update course.');    }  }

The overall code will be like the following.

import 'dart:convert';import 'package:flutter/cupertino.dart';import 'package:flutter_group_project/Service/Model/Service.dart';import 'package:meta/meta.dart';import 'package:http/http.dart' as http;class ServiceDataProvider {  final _baseUrl = 'http://192.168.42.232:5000/api';  final http.Client httpClient;  ServiceDataProvider({@required this.httpClient}) : assert(httpClient != null);  Future<Service> createService(Service service) async {    final response = await httpClient.post(      Uri.http('http://192.168.42.232:5000', '/api/services'),      headers: <String, String>{        'Content-Type': 'application/json; charset=UTF-8',      },      body: jsonEncode(<String, dynamic>{        "serviceName": service.ServiceName,        "description": service.Description,        "category": service.Category,        "initialPrice": service.InitialPrice,        "intermediatePrice":service.IntermediatePrice,        "advancedPrice":service.AdvancedPrice,      }),    );    if (response.statusCode == 200) {      return Service.fromJson(jsonDecode(response.body));    } else {      throw Exception('Failed to create course.');    }  }  Future<List<Service>> getServices() async {    try{     final response = await http.get('${_baseUrl}/services');     if (response.statusCode == 200) {       final services = jsonDecode(response.body) as List;       return services.map((service) => Service.fromJson(service)).toList();     } else {       throw Exception('Failed to load courses');     }   }catch(e){     print("Exception throuwn $e");    }  }  Future<void> deleteService(int  id) async {    final http.Response response = await http.delete(      'http://192.168.43.163:5000/Service/$id',      headers: <String, String>{        'Content-Type': 'application/json; charset=UTF-8',      },    );    if (response.statusCode != 200) {      throw Exception('Failed to delete course.');    }  }  Future<void> updateService(Service service) async {    final http.Response response = await httpClient.put(      'http://192.168.43.163:5000/Service/',      headers: <String, String>{        'Content-Type': 'application/json; charset=UTF-8',      },      body: jsonEncode(<String, dynamic>{        "serviceId":service.id,        "serviceName": service.ServiceName,        "description": service.Description,        "category": service.Category,        "initialPrice": service.InitialPrice,        "intermediatePrice":service.IntermediatePrice,        "advancedPrice":service.AdvancedPrice,      }),    );    if (response.statusCode != 200) {      throw Exception('Failed to update course.');    }  }}

data_provider.dart
this will export the service_data add the following line of code inside.

export 'Service_data.dart';

Bloc Architecture: Data Layer -> Repository

The repository layer is a wrapper around one or more data providers with which the Bloc Layer communicates. It can interact with multiple data providers and perform transformations on the data before handing the result to the business logic layer.

Inside the Repository directory let us create the following two dart files.

image

Then inside the service_repository.dart file we are going to create a funciton for all of the data provider crud methos.
this method will serve as a mediator between the bloc and the data provider.

import 'package:flutter_group_project/Service/Model/Service.dart';import 'package:meta/meta.dart';import '../Service.dart';class ServiceRepository {  final ServiceDataProvider dataProvider;  ServiceRepository({@required this.dataProvider})      : assert(dataProvider != null);  Future<Service> createService(Service service) async {    return await dataProvider.createService(service);  }  Future<List<Service>> getServices() async {    print("This is the getService method");    return await dataProvider.getServices();  }  Future<void> updateService(Service service) async {    await dataProvider.updateService(service);  }  Future<void> deleteService(int  id) async {    await dataProvider.deleteService(id);  }}

The repository.dart file does nothing but exporting the service_repository.dart.

export 'Service_repository.dart';

Bloc Architecture: Business Logic Layer

The business logic layer's responsibility is to respond to input from the presentation layer with new states.This layer can depend on one or more repositories to retrieve data needed to
build up the application state.Think of the business logic layer as the bridge between the user interface (presentation layer) and the data layer.
The business logic layer is notified of events/actions from the presentation layer and then communicates with repository in order to build a new state for the presentation layer to consume.

From the Bloc directory create the following dart files.

image

The bloc state management have three different elements.

  • State
  • Event
  • bloc

State
The State will represent the state for the application. this will be the defined state that the app will possess.

open Service_state.dart file and add the following code inside.

import 'package:equatable/equatable.dart';import 'package:flutter_group_project/Service/Service.dart';class ServiceState extends Equatable {  const ServiceState();  @override  List<Object> get props => [];}class ServiceLoading extends ServiceState {}class ServicesLoadSuccess extends ServiceState{  final List<Service> services;  ServicesLoadSuccess([this.services = const []]);  @override  List<Object> get props => [services];}class ServiceOperationFailure extends ServiceState {}

As you can see from the code we have three different states. ServiceLoading,ServicesLoadSuccess,ServiceOperationFailer

Event
The event means the operation that will take place in the application. this will be the same as the CRUD operation that we have registered in the data provider.

For this open the Service_event.dart file and add the following code inside.

import 'package:equatable/equatable.dart';import 'package:flutter_group_project/Service/Model/Service.dart';import '';abstract class ServiceEvent extends Equatable {  const ServiceEvent();}class ServiceLoad extends ServiceEvent {  const ServiceLoad();  @override  List<Object> get props => [];}class ServiceCreate extends ServiceEvent {  final Service service;  const ServiceCreate(this.service);  @override  List<Object> get props => [service];  @override  String toString() => 'Service Created {service: $service}';}class ServiceUpdate extends ServiceEvent {  final Service service;  const ServiceUpdate(this.service);  @override  List<Object> get props => [service];  @override  String toString() => 'Service Updated {service: $service}';}class ServiceDelete extends ServiceEvent {  final Service service;  const ServiceDelete(this.service);  @override  List<Object> get props => [service];  @override  toString() => 'Service Deleted {service: $service}';}

here we have 4 different Events These are listed below with their correspondence data provider method.

  • ServiceLoad -> getServices()
  • ServiceCreate -> createService()
  • ServiceUpdate -> updateService()
  • ServiceDelete -> deleteService()

bloc

This dart file will map every event invoked by the presentation layer to the state. then it will send the updated state back to the presentation layer.

open the Service_bloc.dart file and add the following code.

import 'package:flutter/cupertino.dart';import 'package:flutter_bloc/flutter_bloc.dart';import 'package:flutter_group_project/Service/Bloc/bloc.dart';import 'package:flutter_group_project/Service/Repository/Service_repository.dart';class ServiceBloc extends Bloc<ServiceEvent, ServiceState> {  final ServiceRepository serviceRepository;  ServiceBloc({@required this.serviceRepository})      : assert(serviceRepository != null),        super(ServiceLoading());  @override  Stream<ServiceState> mapEventToState(ServiceEvent event) async* {    if (event is ServiceLoad) {      print("Service load method");      yield ServiceLoading();      try {        final services = await serviceRepository.getServices();        print("This is the service $services");        yield ServicesLoadSuccess(services);      } catch (_) {        yield ServiceOperationFailure();      }    }    if (event is ServiceCreate) {      try {        await serviceRepository.createService(event.service);        final services = await serviceRepository.getServices();        yield ServicesLoadSuccess(services);      } catch (_) {        yield ServiceOperationFailure();      }    }    if (event is ServiceUpdate) {      try {        await serviceRepository.updateService(event.service);        final services = await serviceRepository.getServices();        yield ServicesLoadSuccess(services);      } catch (_) {        yield ServiceOperationFailure();      }    }    if (event is ServiceDelete) {      try {        await serviceRepository.deleteService(event.service.id);        final services = await serviceRepository.getServices();        yield ServicesLoadSuccess(services);      } catch (e) {        print("Error de,ete=$e");        yield ServiceOperationFailure();      }    }  }}

and finally, there is one file that remained called bloc.dart this file will export all three files once. so in other than importing all three files separately importing only this file will make our code simpler and minimize the line of code.

export 'Service_bloc.dart';export 'Service_state.dart';export 'Service_event.dart';

If you came from the react js web development background, this type of state management is exactly the same as the **React Redux* state management*

  • Bloc -> Reducer
  • State -> State
  • Event -> Action

Bloc Architecture: Presentation Layer

The presentation layer's responsibility is to figure out how to render itself based on one or more bloc states In addition, it should handle user input and application lifecycle events Most applications flows will start with an AppStart event which triggers the application to fetch some data to present to the user
In this scenario, the presentation layer would add an AppStart event.

We are going to build the UI on this step.
In the screen, directory create the following dart files.

image
The main page of the app looks like the following.

Alt Text
First, there will be an import from the above. we are gonna import all the necessary packages we need to integrate the UI with the business logic and for layouts.

import 'package:flutter/material.dart';import 'package:flutter_bloc/flutter_bloc.dart';import 'package:flutter_group_project/Service/Bloc/bloc.dart';import 'package:flutter_group_project/Service/Screen/ServiceCreateUpdateScreen.dart';import 'package:flutter_group_project/Service/Screen/screens.dart';import 'dart:math';

Create a class called ServiceMainScreen and define the class routeName as Static.

class ServiceMainScreen extends StatelessWidget {  static const routeName='/category_screen';}

The first method we are going to use is a buildSectionTitle and this method is used to build a custom text widget for the title.

Widget buildSectionTitle(BuildContext context, String text){    return  Container(      margin: EdgeInsets.symmetric(        vertical: 10,      ),      child: Text('${text}',        style: Theme.of(context).textTheme.headline6,),    );  }

and next, we have here a buildContainer method that used to build a container, we will use this method later.

Widget buildContainer(BuildContext context , Widget child){    return Container(      height: MediaQuery.of(context).size.height * 0.5 ,      width:MediaQuery.of(context).size.width * 0.90 ,      decoration: BoxDecoration(        color:Colors.white,        border:Border.all(            color:Colors.grey        ),        borderRadius: BorderRadius.circular(10),      ),      child:child,    );  }

Original Link: https://dev.to/yared123yared/how-can-we-integrate-flutter-with-net-core-web-api-flutter-bloc-state-management-2ak3

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To