نظر کلی من اینه که نمیشه به wcf گفت پیچیده آخه هدفش فرق میکنه.و در ضمن مگه APIحدوداً همون Rest با معماری خیلی سادهتر نیست؟
نظرات مطالب
services.AddDbContextFactory<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); services.AddScoped<IunitOfWork>(serviceProvider => serviceProvider.GetRequiredService<IDbContextFactory<ApplicationDbContext>>().CreateDbContext());
public interface IUnitOfWork : IDisposable
@inherits OwningComponentBase<IMediator>
A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext System.ObjectDisposedException: Cannot access a disposed object. Object name: 'IServiceProvider'.
using System; using Microsoft.Extensions.Logging; namespace CoreIocServices { public interface ITestService { void Run(); } public class TestService : ITestService { private readonly ILogger<TestService> _logger; public TestService(ILogger<TestService> logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public void Run() { _logger.LogWarning("A Warning from the TestService!"); } } }
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" /> </ItemGroup> </Project>
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\CoreIocServices\CoreIocServices.csproj" /> </ItemGroup> </Project>
using CoreIocServices; using Microsoft.Extensions.DependencyInjection; namespace CoreIocSample01 { class Program { static void Main(string[] args) { var serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); var serviceProvider = serviceCollection.BuildServiceProvider(); var testService = serviceProvider.GetService<ITestService>(); testService.Run(); } private static void ConfigureServices(IServiceCollection services) { services.AddTransient<ITestService, TestService>(); } } }
Exception has occurred: CLR/System.InvalidOperationException An unhandled exception of type 'System.InvalidOperationException' occurred in Microsoft.Extensions.DependencyInjection.dll: 'Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger`1[CoreIocServices.TestService]' while attempting to activate 'CoreIocServices.TestService'.'
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.2</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.2.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\CoreIocServices\CoreIocServices.csproj" /> </ItemGroup> </Project>
private static void ConfigureServices(IServiceCollection services) { services.AddLogging(configure => configure.AddConsole().AddDebug()); services.AddTransient<ITestService, TestService>(); }
CoreIocServices.TestService:Warning: A Warning from the TestService!
namespace BlazorServer.Services { public interface IHotelRoomService { Task<HotelRoomDTO> CreateHotelRoomAsync(HotelRoomDTO hotelRoomDTO); Task<int> DeleteHotelRoomAsync(int roomId); IAsyncEnumerable<HotelRoomDTO> GetAllHotelRoomsAsync(); Task<HotelRoomDTO> GetHotelRoomAsync(int roomId); Task<HotelRoomDTO> IsRoomUniqueAsync(string name); Task<HotelRoomDTO> UpdateHotelRoomAsync(int roomId, HotelRoomDTO hotelRoomDTO); } }
@page "/hotel-room" <div class="row mt-4"> <div class="col-8"> <h4 class="card-title text-info">Hotel Rooms</h4> </div> <div class="col-3 offset-1"> <NavLink href="hotel-room/create" class="btn btn-info">Add New Room</NavLink> </div> </div> @code { }
<li class="nav-item px-3"> <NavLink class="nav-link" href="hotel-room"> <span class="oi oi-list-rich" aria-hidden="true"></span> Hotel Rooms </NavLink> </li>
@page "/hotel-room/create" <h3>HotelRoomUpsert</h3> @code { }
<Project Sdk="Microsoft.NET.Sdk.Web"> <ItemGroup> <ProjectReference Include="..\BlazorServer.Models\BlazorServer.Models.csproj" /> </ItemGroup> </Project>
@using BlazorServer.Models
@page "/hotel-room/create" <div class="row mt-2 mb-5"> <h3 class="card-title text-info mb-3 ml-3">@Title Hotel Room</h3> <div class="col-md-12"> <div class="card"> <div class="card-body"> <EditForm Model="HotelRoomModel"> <div class="form-group"> <label>Name</label> <InputText @bind-Value="HotelRoomModel.Name" class="form-control"></InputText> </div> </EditForm> </div> </div> </div> </div> @code { private HotelRoomDTO HotelRoomModel = new HotelRoomDTO(); private string Title = "Create"; }
<EditForm Model="HotelRoomModel"> <div class="form-group"> <label>Name</label> <InputText @bind-Value="HotelRoomModel.Name" class="form-control"></InputText> </div> <div class="form-group"> <label>Occupancy</label> <InputNumber @bind-Value="HotelRoomModel.Occupancy" class="form-control"></InputNumber> </div> <div class="form-group"> <label>Rate</label> <InputNumber @bind-Value="HotelRoomModel.RegularRate" class="form-control"></InputNumber> </div> <div class="form-group"> <label>Sq ft.</label> <InputText @bind-Value="HotelRoomModel.SqFt" class="form-control"></InputText> </div> <div class="form-group"> <label>Details</label> <InputTextArea @bind-Value="HotelRoomModel.Details" class="form-control"></InputTextArea> </div> <div class="form-group"> <button class="btn btn-primary">@Title Room</button> <NavLink href="hotel-room" class="btn btn-secondary">Back to Index</NavLink> </div> </EditForm>
<EditForm Model="HotelRoomModel" OnSubmit="HandleHotelRoomUpsert"> </EditForm> @code { private HotelRoomDTO HotelRoomModel = new HotelRoomDTO(); private async Task HandleHotelRoomUpsert() { } }
<EditForm Model="HotelRoomModel" OnValidSubmit="HandleHotelRoomUpsert"> <DataAnnotationsValidator /> @*<ValidationSummary />*@ <div class="form-group"> <label>Name</label> <InputText @bind-Value="HotelRoomModel.Name" class="form-control"></InputText> <ValidationMessage For="()=>HotelRoomModel.Name"></ValidationMessage> </div> <div class="form-group"> <label>Occupancy</label> <InputNumber @bind-Value="HotelRoomModel.Occupancy" class="form-control"></InputNumber> <ValidationMessage For="()=>HotelRoomModel.Occupancy"></ValidationMessage> </div> <div class="form-group"> <label>Rate</label> <InputNumber @bind-Value="HotelRoomModel.RegularRate" class="form-control"></InputNumber> <ValidationMessage For="()=>HotelRoomModel.RegularRate"></ValidationMessage> </div>
@using BlazorServer.Services
@page "/hotel-room/create" @inject IHotelRoomService HotelRoomService @inject NavigationManager NavigationManager @code { private HotelRoomDTO HotelRoomModel = new HotelRoomDTO(); private string Title = "Create"; private async Task HandleHotelRoomUpsert() { var roomDetailsByName = await HotelRoomService.IsRoomUniqueAsync(HotelRoomModel.Name); if (roomDetailsByName != null) { //there is a duplicate room. show an error msg. return; } var createdResult = await HotelRoomService.CreateHotelRoomAsync(HotelRoomModel); NavigationManager.NavigateTo("hotel-room"); } }
@page "/hotel-room" @inject IHotelRoomService HotelRoomService <div class="row mt-4"> <div class="col-8"> <h4 class="card-title text-info">Hotel Rooms</h4> </div> <div class="col-3 offset-1"> <NavLink href="hotel-room/create" class="btn btn-info">Add New Room</NavLink> </div> </div> <div class="row mt-4"> <div class="col-12"> <table class="table table-bordered table-hover"> <thead> <tr> <th>Name</th> <th>Occupancy</th> <th>Rate</th> <th> Sqft </th> <th> </th> </tr> </thead> <tbody> @if (HotelRooms.Any()) { foreach (var room in HotelRooms) { <tr> <td>@room.Name</td> <td>@room.Occupancy</td> <td>@room.RegularRate.ToString("c")</td> <td>@room.SqFt</td> <td></td> </tr> } } else { <tr> <td colspan="5">No records found</td> </tr> } </tbody> </table> </div> </div> @code { private List<HotelRoomDTO> HotelRooms = new List<HotelRoomDTO>(); protected override async Task OnInitializedAsync() { await foreach(var room in HotelRoomService.GetAllHotelRoomsAsync()) { HotelRooms.Add(room); } } }
// Do NOT do this anymore //services.AddDbContext(o => o.UseSQlite("filename.db")); // But instead do this: services.AddDbContextFactory(o => o.UseSQlite("filename.db"));
public class MyService { private readonly IDbContextFactorey _contextFactory; public MyService(IDbContextFactory contextFactory) { _contextFactory = contextFactory; } // create a new context for each operation / unit of work public async Task DoSomethingAsync() { using (var ctx = _contextFactory.CreateDbContext()) { // this using clause contains your unit of work } } }
> npm i axios --save > npm i react-toastify --save
import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css";
render() { return ( <React.Fragment> <ToastContainer />
import { apiUrl } from "../config.json"; import http from "./httpService"; export function getGenres() { return http.get(apiUrl + "/genres"); }
{ "apiUrl": "https://localhost:5001/api" }
import { getGenres } from "../services/fakeGenreService";
import { getGenres } from "../services/genreService";
Uncaught TypeError: Object is not a function or its return value is not iterable
async componentDidMount() { const { data } = await getGenres(); const genres = [{ _id: "", name: "All Genres" }, ...data]; this.setState({ movies: getMovies(), genres }); }
import { apiUrl } from "../config.json"; import http from "./httpService"; const apiEndpoint = apiUrl + "/movies"; function movieUrl(id) { return `${apiEndpoint}/${id}`; } export function getMovies() { return http.get(apiEndpoint); } export function getMovie(movieId) { return http.get(movieUrl(movieId)); } export function saveMovie(movie) { if (movie.id) { return http.put(movieUrl(movie.id), movie); } return http.post(apiEndpoint, movie); } export function deleteMovie(movieId) { return http.delete(movieUrl(movieId)); }
import { getMovies, deleteMovie } from "../services/movieService";
async componentDidMount() { const { data } = await getGenres(); const genres = [{ id: "", name: "All Genres" }, ...data]; const { data: movies } = await getMovies(); this.setState({ movies, genres }); }
handleDelete = async movie => { const originalMovies = this.state.movies; const movies = originalMovies.filter(m => m.id !== movie.id); this.setState({ movies }); try { await deleteMovie(movie.id); } catch (ex) { if (ex.response && ex.response.status === 404) { console.log(ex); toast.error("This movie has already been deleted."); } this.setState({ movies: originalMovies }); //undo changes } };
import { toast } from "react-toastify";
import { getGenres } from "../services/fakeGenreService"; import { getMovie, saveMovie } from "../services/fakeMovieService";
import { getGenres } from "../services/genreService"; import { getMovie, saveMovie } from "../services/movieService";
async componentDidMount() { const { data: genres } = await getGenres(); this.setState({ genres }); const movieId = this.props.match.params.id; if (movieId === "new") return; const { data: movie } = await getMovie(movieId); if (!movie) return this.props.history.replace("/not-found"); this.setState({ data: this.mapToViewModel(movie) }); }
async populateGenres() { const { data: genres } = await getGenres(); this.setState({ genres }); } async populateMovie() { try { const movieId = this.props.match.params.id; if (movieId === "new") return; const { data: movie } = await getMovie(movieId); this.setState({ data: this.mapToViewModel(movie) }); } catch (ex) { if (ex.response && ex.response.status === 404) this.props.history.replace("/not-found"); } } async componentDidMount() { await this.populateGenres(); await this.populateMovie(); }
doSubmit = async () => { await saveMovie(this.state.data); this.props.history.push("/movies"); };
{ "host": "http://localhost:8008" }
import { Observable } from 'rxjs/Observable'; import { Inject, Injectable } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; @Injectable() export class AppConfigService { constructor(private http: Http) { } private config: Object = null; get apiRoot() { return this.getProperty('host'); // <--- THIS GETS CALLED FIRST } load(): Promise<any> { console.log('get user called'); const promise = this.http.get('assets/config.json').map((res) => res.json()).toPromise(); promise.then(config => { this.config = config; // <--- THIS RESOLVES AFTER console.log(this.config); }); return promise; } private getProperty(property: string): any { //noinspection TsLint if (!this.config) { throw new Error('Attempted to access configuration property before configuration data was loaded, please implemented.'); } if (!this.config[property]) { throw new Error(`Required property ${property} was not defined within the configuration object. Please double check the assets/config.json file`); } return this.config[property]; } }
export function init(config: AppConfigService) { return () => { return config.load(); }; }
Providers:[ …, AppConfigService, { provide: APP_INITIALIZER, useFactory: init, multi: true, deps: [AppConfigService] } …, ]
@Injectable() export class DashboardService { private tagUrl = ''; constructor(private http: Http,private AppConfig:AppConfigService) { this.tagtUrl = this.AppConfig.apiRoot+"/myApiUrl"; …. }
{ provide: APP_INITIALIZER, useFactory: init, multi: true, deps: [AppConfigService] }, { provide: APP_INITIALIZER, useFactory: initIdentity, multi: true, deps: [IdentityService] }, AppConfigService, IdentityService,