我有一个.net Core Web-api应用程序。 我有意从控制器返回异常,但是在订阅的错误处理中看不到该异常被处理。 这是我的代码(手动复制,因此可能会出现输入错误): 控制器:
public IActionResult getSomeErrorAsTest()
{
try
{
throw new Exception("Serer error");
}
catch(Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, new List<string>());
//throw ex;
}
}
角度服务:
export class MyService
{
MyDataSubject = new Subject<any[]>();
MyDataChanged :Observable>any[]> = this.MyDataSubject.asObservable();
subscribe :Subscription;
constructor(private httpClient : HttpClient)
{
this.subscribe = timer(0, 30000).pipe(
switchMap(()=>
this.getData())).subscribe();
}
getData()
{
return this.httpClient.get<any[]>(<controller url>)
.pipe(
tap(res =>
{
this.MyDataSubject.next(res);
}),
catchError(error =>
{
debugger;//I would expect to catch the debugger here, but nothing happens
return throwError(error);
})
)
}
}
组件:
export class MyComponent (private mySrv : MyService)
{
getMyData()
{
let sub =this.mySrv.MyDataChanged.subscribe(result => doSomething(),
error=> popUpAlert());
}
}
答案 0 :(得分:1)
正如@fridoo指出的那样,您的组件正在订阅一个可观察到的流,该流永远不会发出任何错误。这是因为您有两个单独的可观察对象。
您实际上不需要维护主题并手动发出。您可以直接通过getData
方法来轮询并公开可观察到的更改。
您甚至可以考虑将getData()
设为私有,仅允许消费者使用MyDataChanged
可观察的状态。 (也许重命名为data$
)
export class MyService {
data$: Observable<any[]> = timer(0, 30000).pipe(
switchMapTo(this.getData()),
distinctUntilChanged(compareFn)
);
constructor(private httpClient: HttpClient) { }
private getData() {
return this.httpClient.get(<controller url>).pipe(
retry(2)
);
}
compareFn(oldVal: any[], newVal: any[]) {
// add logic to determine if emission
// is considered to be different.
}
}
注意,您不必订阅服务。您也不需要单独的主题。这样做还有一个好处,就是可以变得懒惰,因为在实际订阅了data$
观察对象之前,http调用不会开始轮询。
您可以选择在getData()
方法或组件中捕获错误。
使用过的操作员:
switchMapTo
-由于您没有使用从计时器传递的参数,因此可以使用这种更简洁的方法代替常规的switchMap
distinctUntilChanged
-将滤除相同的连续发射。您提供“比较功能”来确定某个值是否被认为与先前的值不同。
retry
-方便在发生错误时重试HTTP调用。
现在,在您的组件中:
export class MyComponent {
constructor(private mySrv: MyService){ }
getMyData() {
const sub = this.mySrv.data$.subscribe(
result => doSomething(),
error => popUpAlert()
);
}
}
如果我不提到在模板中利用async
管道而不是在控制器中管理订阅,通常会更容易。
这种情况看起来像:
export class MyComponent {
constructor(private mySrv: MyService){ }
data$ = this.mySrv.data$.pipe(
// tap(data => doSomething(data)), <-- hopefully you don't even need this
catchError(error => {
popUpAlert(error);
})
);
}
然后是模板:
<ul>
<li *ngFor="let item of data$ | async> {{ item.property }}</li>
</ul>