I'm trying to think of a pattern I can use.
I want to be able to have a middleman module that takes in a kind of state of a game. Given that state, call a certain method that resides in anotehr module.
What pattern could I use for this?
For example, I want to be able to take in a state of "computer always wins" and based on that state type, I'll call someOtherModule.makeComputerMove(). In the future maybe we want to be able to set the game to a mode where the computer doesn't always win. Well then we could send in a state of "normal game" or something like that which would just call computerAlwaysWins.makeComputerMove() from a different use case module such as normalGame.makeComputerMove()
get the idea?
I can't think of any patterns to provide such a thing...probably because I don't know a lot of them.
You should use State pattern probably with combination of Observer.
public class GameStateContext {
PlayerState Player {get;set; }
// other properties that need to be shared
}
public interface IGameController {
void GoToState(State state)
}
public interface IGameState {
void Start();
void Update();
}
public abstract class GameStateBase : IGameState {
protected GameStateContext _context;
protected IGameController _parent;
public GameStateBase(GameStateContext context, IGameController parent) {
this._context = context;
this._parent = parent;
}
public virtual void Start() {
}
public virtual void Update() {
}
}
public class BonusLevelState : GameStateBase {
public public MainMenuState (GameStateContext context, IGameController parent) : base (context, parent) {
}
public override void Update() {
if(_context.Player.Health == 0) {
_parent.GoToState(GameStates.GameOver);
}
}
}
public GameController : IGameController {
public enum GameStates {
BonusLevel,
InitialState,
....
}
private IGameState currentState;
public GameController() {
// create diferent states
...
currentState = GetState(GameStates.InitialState);
}
public void Update {
currentState.Update();
}
public GoToState(State state) {
currentState = GetState(state);
}
}
I hope you catch an idea, good luck!
Related
I've made a facade service to avoid multiple calls to the API.
It call retrieveMyUser each time the request is made.
If the request has never been made it store the value usingBehaviorSubject. If it has already been made it take the value stored.
I want to clear the data of my BehaviorSubject in auth.service.ts when a user logout. My try to do that is that I call a clearUser() method from facade-service.ts.
facade-service.ts :
...
export class UserServiceFacade extends UserService {
public readonly user = new BehaviorSubject(null);
retrieveMyUser() {
console.log(this.user.value);
return this.user.pipe(
startWith(this.user.value),
switchMap(user => (user ? of(user) : this.getUserFromServer())),
take(1)
)
}
private getUserFromServer() {
return super.retrieveMyUser(null, environment.liveMode).pipe(tap(user => this.storeUser(user)));
}
public clearUser() {
console.log("cleared");
this.storeUser(null)
console.log(this.user.value); // Output null
}
private storeUser(user: V2UserOutput) {
this.user.next(user);
}
}
auth.service.ts :
...
logout() {
var cognitoUser = this.userPool.getCurrentUser();
if (cognitoUser) {
this.userServiceFacade.clearUser()
cognitoUser.signOut();
}
this._router.navigate(['/login']);
}
...
The method clearUser() in auth.service.ts is well called and print cleared correctly.
But when I login, after I logout the console.log(this.user.value); in retrieveMyUser still output the previous value. It was null when at logout though.
So, how do I clear BehaviorSubject cache or to reset BehaviorSubject from another service ?
There are many things in your code which sound weird at reading:
You shouldn't access immediately to the value of a BehaviorSubject without using the asObservable() as recommended by ESLint here.
Instead, you could use another variable which will keep the latest value for the user.
You should use the power of TypeScript in order to help you with types definition and quality code (in my opinion).
The use of a BehaviorSubject with a startWith operator can be simplified using a ReplaySubject with a bufferSize of 1 (replay the latest change)
Your subject acting like a source storage should be private in order to limit the accessibility from outside.
I took your code and make some updates from what I said above:
export class UserServiceFacade extends UserService {
private _user: V2UserOutput;
private readonly _userSource = new ReplaySubject<V2UserOutput>(1);
public get user(): V2UserOutput { // Use for accessing to the user data without the use of an observable.
return this._user;
}
constructor() {
super();
this.clearUser(); // It will make your ReplaySubject as "alive".
}
public retrieveMyUser$(): Observable<V2UserOutput> {
return this._userSource.asObservable()
.pipe(
switchMap(user => (user ? of(user) : this.getUserFromServer())),
take(1)
);
}
private getUserFromServer(): Observable<V2UserOutput> {
return super.retrieveMyUser(null, 'environment.liveMode')
.pipe(
tap(user => this.storeUser(user))
);
}
public clearUser() {
console.log('cleared');
this.storeUser(null);
}
private storeUser(user: V2UserOutput) {
this._user = user;
this._userSource.next(user);
}
}
Cheers!
I am trying to learn how to use .NET and React and make a single page application where the React front end speaks to the .NET back end. I have decided to create a simple thermostat application where the user can view a thermostat temperature and press buttons which will increase and decrease that temperature. Before I even get that far though I am struggling to get the data from my Controller class to display on my front end. Here is my code:
ThermostatController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace ThermostatDotNet.Controllers
{
[Route("api/[controller]")]
public class ThermostatController : Controller
{
private int _Temperature { get; set; }
public ThermostatController(int _temperature)
{
_Temperature = _temperature;
}
[HttpGet, Route("GetTemp")]
public int GetTemp()
{
return _Temperature;
}
[HttpGet, Route("Increase")]
public int Increase()
{
_Temperature += 1;
return _Temperature;
}
}
}
Thermostat.js
import React, { Component } from 'react';
export class Thermostat extends Component {
state = {
temp: ""
}
displayTemp() {
fetch("api/Thermostat/GetTemp")
.then(response => response.text())
.then(data => {
this.setState({ temp: data });
});
}
render () {
return (
<div>
<h1>Thermostat</h1>
<p>The temperature is:{this.state.temp}</p>
</div>
);
}
}
The problem I am having is that I want to display the current temperature of the Thermostat when the user visits the application. I am not sure how to create that new thermostat and display the temperature in my React code? I have looked at other Stack Overflow answers but am still finding it difficult to implement here (I'm very new to React and .NET). Can anyone help? Thank you :)
UPDATE
After receiving the following error InvalidOperationException: Unable to resolve service for type 'System.Int32' while attempting to activate 'ThermostatDotNet.Controllers.ThermostatController'. I managed to fix this by using an interface and implementing this:
[Route("api/[controller]")]
public class ThermostatController : Controller
{
private readonly ITemperature _temperature;
private int _Temperature { get; set; }
public ThermostatController(ITemperature temperature)
{
_temperature = temperature;
}
[HttpGet, Route("GetTemp")]
public int GetTemp()
{
return _Temperature;
}
}
First of all you need to return number from your controller like this.
Using return Ok();
[Route("api/[controller]")]
public class ThermostatController : Controller
{
public ThermostatController()
{
}
[HttpGet, Route("GetTemp")]
public int GetTemp()
{
return Ok(1);
}
}
Update: Then in your react use componentDidMount make sure you console.log(data) to see the data then use data.something to display data
componentDidMount() {
fetch("api/Thermostat/GetTemp")
.then(data => {
console.log(data);
this.setState({ temp: data });
});
}
You can read a document here
Let's say we have a service like this one:
SupermanService {
private _superman: Hero;
public supermanReplaced = new EventEmitter<Hero>();
public supermanPropertyUpdated = new EventEmitter<Hero>();
public get superman(): Hero {
return this._superman;
}
public set superman(superman): void {
this._superman = superman;
this.supermanReplaced.emit(superman);
}
public updateSupermanProperty(key: string, val: string | number): Hero {
this._superman[key] = val;
this.supermanPropertyUpdated.emit(superman);
return this._superman;
}
}
Is there some way to detect supermanPropertyUpdated without using the updateSupermanProperty() function but by e.g. setting this.superman.power = 10?
I found some posts that suggest the KeyValueDiffer in combination with the DoCheck hook, but that is not available for services.
You can use get/set methods.
In your example:
class SupermanService {
private _superman: Hero;
public supermanReplaced = new EventEmitter<Hero>();
public supermanPropertyUpdated = new EventEmitter<Hero>();
public set power(level: integer) {
this._superman.power = level;
this._supermanPropertyUpdated.emit(this._superman);
}
public get superman(): Hero {
return this._superman;
}
public set superman(superman: Hero): void {
this._superman = superman;
this.supermanReplaced.emit(superman);
}
public updateSupermanProperty(key: string, val: string | number): Hero {
this._superman[key] = val;
this._supermanPropertyUpdated.emit(superman);
return this._superman;
}
}
After this you can use:
SupermanService.power = 10;
and all the listeners will be notified
Update
Another implementation to solve this problem is modifying your Hero class adding a public EventEmitter property and subscribing to this from your service. Assign a setter for each property on your Hero class and emit the change like Output and in your service you can emit the changes.
class Hero {
public onPropertyChange = new EventEmitter<Hero>();
private _name: string;
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
this.onPropertyChange.emit(this);
}
}
class SupermanService {
private _superman: Hero;
public supermanReplaced = new EventEmitter<Hero>();
public get superman(): Hero {
return this._superman;
}
public set superman(superman: Hero): void {
this._superman = superman;
this.supermanReplaced.emit(superman);
}
public get supermanPropertyUpdated(): EventEmitter<Hero> {
return this._superman.onPropertyChange;
}
}
I have multiple methods with different signature, and each method has a try-catch block with custom log exception. (Same structure on multiple controllers).
public class TestController : BaseController
{
public static ActionResult One(int param1, string param2)
{
try
{
// Do something
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
}
return View("ViwName1");
}
public static ActionResult Two(Date param3, bool param4)
{
try
{
// Do something
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
}
return View("ViwName2");
}
}
I wonder if there's a way to avoid try-catch block for every method and execute another
public class TestController : BaseController
{
public static ActionResult One(int param1, string param2)
{
// Do something (*)
// Call "ActionWithTryCatch" method that has a "function argument" to "Do something (*)"
}
public ActionResult ActionWithTryCatch(MyDelegate del, string viewName)
{
try
{
return del.Invoke();
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
}
return View(viewName);
}
}
¿How can I do that? I've seen examples using delegates but I understand that's strongly typed, so didn't find a way to do that. Thanks!
The pattern that you are describing is close to a form of Aspect Oriented Programming (AOP). However, if you just want to apply specific Try Catch error handling logic to all actions on your controller then it's probably not worth it for you to pull in a whole AOP framework. Instead you could leverage the HandleErrorAttribute or override the OnException method of the controller class.
For example your could write your controller like this:
public class TestController
{
private TestService service;
public TestController(TestService service)
{
this.service = service;
}
public ActionResult One(int param1, string param2)
{
this.service.MethodOne(param1, param2);
return View("ViwName1");
}
public ActionResult Two(Date param3, bool param4)
{
this.service.MethodTwo(param3, param4);
return View("ViwName2");
}
protected override void OnException(ExceptionContext filterContext)
{
LogException(filterContext.Exception.Message);
AddModelError(filterContext.Exception.Message);
var errorView = new ViewResult { ViewName = "~/Path/To/Error/View" };
filterContext.Result = errorView;
}
}
If you wanted to abstract it out even more then you could just move the overridden OnException logic into a base controller class and then have all of your controller inherit from the base controller.
If you want to see some additional methods of unified error handling in MVC then check out this blog too: https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging
UPDATE
Per my comment, if you insist on implementing the pattern you are describing you could use this modified version of gilmishal's answer.
public class TestController
{
private TestService service;
public TestController(TestService service)
{
this.service = service;
}
public ActionResult One(int param1, string param2)
{
return this.ActionWithTryCatch(() => this.service.MethodOne(param1, param2), "ViwName1");
}
public ActionResult Two(Date param3, bool param4)
{
return this.ActionWithTryCatch(() => this.service.MethodTwo(param3, param4), "ViwName2");
}
public IActionResult ActionWithTryCatch(Action action, string viewName)
{
try
{
action.Invoke();
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
}
return View(viewName);
}
}
this method you created won't work properly if you need to pass parameters to this function in js - so I am assuming you are calling only parameterless methods.
in that case you could use Func<IActionResult> instead of MyDelegate.
public TResult ActionWithTryCatch<TResult>(Func<TResult> del, string viewName)
{
try
{
return del.Invoke();
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
throw;
}
}
this will be more similar to your javascript implementation, and will return a 500 http result upon unhandledexception.
You should call it like this, if you want IActionResult return type -
ActionWithTryCatch<IActionResult>(MethodThatReturnsIActionResult, viewName);
I recommand you look into generics
In my index.html page, a variable in the script is hard coded. I want to get it from application.properties file but have no idea how to. It would helpful if anyone could provide me a solution.
I have attached the example. Hope to help.
Application
#SpringBootApplication
public class Application {
public static void main(String... args) {
SpringApplication.run(Application.class);
}
}
PropertiesController
#RestController
public class PropertiesController {
#Autowired
private UIProperty uiProperty;
#RequestMapping("properties")
public UIProperty getProperties() {
return uiProperty;
}
}
UIProperty
#Component
#ConfigurationProperties(prefix = "ui.label")
public class UIProperty {
private String user;
private String password;
public void setUser(String user) {
this.user = user;
}
public String getUser() {
return user;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
}
application.properties
ui.label.user=user
ui.label.password=password
database.user=
database.password=
I'd create a RestController to expose ConfigurationProperties. But be sure to properly secure it as well as limit in its scope not to disclose confidential data like db access credentials.