I'm creating a factory service which provides me couple function like
var myApp = angular.module('panelServices', ['ngResource']);
myApp.factory('myService', [...]{
function myService(){
this.list = [];
}
myService.prototype.method1: fn() {} ,
...
myService.prototype.methodn: fn() {},
return myService;
});
The I Inject myService via DI into my controllers and use new myService() to instanciate a new instance of myService.
I did not find another way to do this, I was thinking of "copying" the service into e.g.: anotherService (based on the fact that service are singletons).
My goal is to have a service to use for different models (they do not share data, only methods)-
Please tell me if I did not explain well, thanks in advance.
For multiple instance of service you can use $injector.instantiate
myApp.factory('myService', function($injector){
function myService(){
this.list = [];
}
myService.prototype.method1: fn() {} ,
...
myService.prototype.methodn: fn() {},
return function() {
return $injector.instantiate(myService);
};
});
And then in controller
myApp.controller('myController', function(myService){
var service = new myService();
//other code
});
in another controller
myApp.controller('anotherController', function(myService){
var service = new myService();
//other code
});
new myService() it always give you new instance. See this plunker
Related
In ASP.NET Core 5 I had a custom Action Result as follows:
public class ErrorResult : ActionResult {
private readonly IList<Error> _errors;
public ErrorResult(IList<Error> errors) {
_errors = errors;
}
public override async Task ExecuteResultAsync(ActionContext context) {
// Code that creates Response
await result.ExecuteResultAsync(context);
}
}
Then on a Controller action I would have:
return new ErrorResult(errors);
How to do something similar in NET 6 Minimal APIs?
I have been looking at it and I think I should implement IResult.
But I am not sure if that is the solution or how to do it.
I have recently been playing around with minimal APIs and and working on global exception handling. Here is what I have come up with so far.
Create a class implementation of IResult
Create a constructor which will take an argument of the details you want going into your IResult response. APIErrorDetails is a custom implementation of mine similar to what you'd see in ProblemDetails in MVC. Method implementation is open to whatever your requirements are.
public class ExceptionAllResult : IResult
{
private readonly ApiErrorDetails _details;
public ExceptionAllResult(ApiErrorDetails details)
{
_details = details;
}
public async Task ExecuteAsync(HttpContext httpContext)
{
var jsonDetails = JsonSerializer.Serialize(_details);
httpContext.Response.ContentType = MediaTypeNames.Application.Json;
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(jsonDetails);
httpContext.Response.StatusCode = _details.StatusCode;
await httpContext.Response.WriteAsync(jsonDetails);
}
}
Return result in your exception handling middleware in your Program.cs file.
app.UseExceptionHandler(
x =>
{
x.Run(
async context =>
{
// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-6.0
var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>();
// Whatever you want for null handling
if (exceptionFeature is null) throw new Exception();
// My result service for creating my API details from the HTTP context and exception. This returns the Result class seen in the code snippet above
var result = resultService.GetErrorResponse(exceptionFeature.Error, context);
await result.ExecuteAsync(context); // returns the custom result
});
}
);
If you still want to use MVC (Model-View-Controller), you still can use Custom ActionResult.
If you just want to use Minimal APIs to do the response, then you have to implement IResult, Task<IResult> or ValueTask<IResult>.
app.MapGet("/hello", () => Results.Ok(new { Message = "Hello World" }));
The following example uses the built-in result types to customize the response:
app.MapGet("/api/todoitems/{id}", async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound())
.Produces<Todo>(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound);
You can find more IResult implementation samples here: https://github.com/dotnet/aspnetcore/tree/main/src/Http/Http.Results/src
Link: Minimal APIs overview | Microsoft Docs
I'm refactoring my code to use Refit for my calls to the WebApi service. The interface is set up and I also created a delegating handler:
public class AuthHandler : DelegatingHandler
{
private readonly TokenProvider tokenProvider;
private readonly ISessionStorageService sessionStorage;
public AuthHandler (
TokenProvider tokenProvider,
ISessionStorageService sessionStorage)
{
this.tokenProvider = tokenProvider ?? throw new ArgumentNullException(nameof(tokenProvider));
this.sessionStorage = sessionStorage ?? throw new ArgumentNullException(nameof(sessionStorage));
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ct)
{
var someToken = await sessionStorage.GetItemAsync<string>("sometoken");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenProvider.AccessToken);
request.Headers.Add("someToken", someToken);
return await base.SendAsync(request, ct).ConfigureAwait(false);
}
}
And in Startup.cs:
services.AddBlazoredSessionStorage();
services.AddScoped<TokenProvider>();
services.AddScoped<AuthHandler>();
services.AddRefitClient<IApiService>().ConfigureHttpClient(options =>
{
options.BaseAddress = new Uri(Configuration["Server:Url"]);
options.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}).AddHttpMessageHandler<AuthHandler>();
I have a razor component and I want to use the service above so I injected the services and did:
#code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var list = await myService.GetListAsync();
}
}
}
Also, in _Host.cshtml:
<environment include="Staging,Production">
<component render-mode="ServerPrerendered" type="typeof(App)" param-InitialState="tokens" />
</environment>
<environment include="Development">
<component render-mode="Server" type="typeof(App)" param-InitialState="tokens" />
</environment>
However I get the following exception:
System.InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.
So, just to make sure if I have values or not I added the following before the call to the api:
var someToken = await sessionStorage.GetItemAsync<string>("sometoken");
var accessToken = tokenProvider.AccessToken;
And I DO have values in both variables.
So why can't I access the session storage from the delegating handler? And why is token provider instance instantiated but the properties all null (also in the handler)?
EDIT
I only need one place to keep my tokens. It doesn't matter if it's the token provider or the session storage, as long as it works in blazor pages/componenents and other services.
UPDATE 1
One can skip DI and create the service like this:
var service = RestService.For<IMyService>(new HttpClient(new AuthHandler(tokenProvider, sessionStorage))
{
BaseAddress = new Uri(myUrl)
}
);
This will work as expected. However, it would be much more better to use DI. The problem might either be in Blazor or in Refit.
I think I have found a working solution to the problem.
Instead of relying on the HttpClientFactory used by Refit, I created my own DI logic.
Previous:
Uri apiBaseUri = dataAccessLayerConfiguration.API.BaseUrl;
foreach (Type repositoryType in repositoryTypes)
{
services
.AddRefitClient(repositoryType)
.ConfigureHttpClient((httpClient) => httpClient.BaseAddress = apiBaseUri)
.AddHttpMessageHandler<RequestHeaderHandler>();
}
Current:
foreach (Type repositoryType in repositoryTypes)
{
services.AddTransient(
repositoryType,
(provider) =>
{
return
RepositoryFactory.Create(
repositoryType,
configuration,
provider.GetRequiredService<ITokenCacheProvider>(),
() => provider.GetRequiredService<ICurrentUser>());
});
}
The RepositoryFactory I use creates the HttpClients for each API interface:
return
RestService.For<TRepository>(
new HttpClient(
new RequestHeaderHandler(tokenCacheProvider, fetchCurrentUserDelegate)
{
InnerHandler = new HttpClientHandler()
},
true)
{
BaseAddress = configuration.DataAccessLayer.API.BaseUrl
});
I currently get the current user in the code of my layout in the OnParametersSet() method. I'm not completely satisfied with it yet, but for now it's enough for me. However, it is important not to inject the user object directly when creating HttpClient, but only a delegate (or a Func<>) which then resolves the user object if needed.
This way I was able to work around the scope issue of Refit/HttpClientFactory, but still continue to work with Dependency Injection. It may not be a one hundred percent solution for everyone, but it could be enough to possibly find the right direction for your own project.
I'm unit testing my API service and all is well using the MockRquestContext. The calls to this.GetSession() always returns an IAuthSession, but I have a custom AuthUserSession and as far as I can tell, there's no way to create an instance of my custom AuthUserSession and add it to the mock context. Is this possible?
var service = container.Resolve<AgencyCaseService>();
service.SetResolver(new BasicResolver(container));
var context = new MockRequestContext() { ResponseContentType = ContentType.Json };
//Something like this
MyCustomAuthSession session = new MyCustomAuthSession() { set some values}
context.AuthSession = session//this doesn't exist but it's the type of thing i need to do
service.RequestContext = context;
The Session isn't on the Request Context, it requires a mixture of ICacheClient, SessionFeature and HttpRequest cookies to create.
You can look at the implementation for the way to mock it inside a Service, which shows it first tries to resolve it in a Container:
private object userSession;
protected virtual TUserSession SessionAs<TUserSession>()
{
if (userSession == null)
{
userSession = TryResolve<TUserSession>(); //Easier to mock
if (userSession == null)
userSession = Cache.SessionAs<TUserSession>(Request, Response);
}
return (TUserSession)userSession;
}
So to mock it you could just do:
container.Register(new MyCustomAuthSession() { /* set some values*/ });
http://docs.phalconphp.com/en/0.6.0/reference/odm.html
Setting multiple databases¶
In Phalcon, all models can belong to the same database connection or have an individual one. Actually, when Phalcon\Mvc\Collection needs to connect to the database it requests the “mongo” service in the application’s services container. You can overwrite this service setting it in the initialize method:
<?php
//This service returns a mongo database at 192.168.1.100
$di->set('mongo1', function() {
$mongo = new Mongo("mongodb://scott:nekhen#192.168.1.100");
return $mongo->selectDb("management");
});
//This service returns a mongo database at localhost
$di->set('mongo2', function() {
$mongo = new Mongo("mongodb://localhost");
return $mongo->selectDb("invoicing");
});
Then, in the Initialize method, we define the connection service for the model:
<?php
class Robots extends \Phalcon\Mvc\Collection
{
public function initialize()
{
$this->setConnectionService('management'); // here?
}
}
You are correct. The documentation was wrong. The correct usage is to set the appropriate service name (not the collection) using the setConnectionService.
http://docs.phalconphp.com/en/latest/reference/odm.html
<?php
// This service returns a mongo database at 192.168.1.100
$di->set(
'mongo1',
function()
{
$mongo = new Mongo("mongodb://scott:nekhen#192.168.1.100");
return $mongo->selectDb("management");
}
);
// This service returns a mongo database at localhost
$di->set(
'mongo2',
function()
{
$mongo = new Mongo("mongodb://localhost");
return $mongo->selectDb("invoicing");
}
);
Then, in the Initialize method, we define the connection service for the model:
.. code-block:: php
<?php
class Robots extends \Phalcon\Mvc\Collection
{
public function initialize()
{
$this->setConnectionService('mongo1');
}
}
In Funq and probably most other IoC containers I can simply do this to configure a type:
container.Register<ISomeThing>(c => new SomeThing());
How could I quickly extend MEF (or use existing MEF functionality) to do the same without using attributes.
Here is how I thought I could do it:
var container = new CompositionContainer();
var batch = new CompositionBatch();
batch.AddExport<ISomeThing>(() => new SomeThing());
batch.AddExportedValue(batch);
container.Compose(batch);
With this extension method for CompositionBatch:
public static ComposablePart AddExport<TKey>(this CompositionBatch batch, Func<object> func)
{
var typeString = typeof(TKey).ToString();
return batch.AddExport(
new Export(
new ExportDefinition(
typeString,
new Dictionary<string, object>() { { "ExportTypeIdentity", typeString } }),
func));
}
If I later do:
var a = container.GetExport<ISomeThing>().Value;
var b = container.GetExport<ISomeThing>().Value;
Both instance are the same. How can I force (configure) them to be different instances?
If this is not the way to go, how would I do this in MEF?
I would imagine the key is to add the delegate to the container, e.g.:
container.AddExportedValue<Func<ISomething>>(() => new Something());
That way you can grab the delegate and execute it:
var factory = container.GetExport<Func<ISomething>>();
ISomething something = factory();
Of course, MEF (Silverlight) does provide a native ExportFactory<T> (and ExportFactory<T,TMetadata> type that supports the creation of new instances for each call to import. You can add support for this by downloading Glen Block's ExportFactory for .NET 4.0 (Desktop) library.
If you don't want to use attributes, you can use this trick (based on Mark Seemann's blogpost).
First, create a generic class like this:
[PartCreationPolicy(CreationPolicy.NonShared)]
public class MefAdapter<T> where T : new()
{
private readonly T export;
public MefAdapter()
{
this.export = new T();
}
[Export]
public virtual T Export
{
get { return this.export; }
}
}
Now you can register any class you want in the container, like this:
var registeredTypesCatalog = new TypeCatalog(
typeof(MefAdapter<Foo>),
typeof(MefAdapter<Bar>),
...);
var container = new CompositionContainer(catalog);
Alternatively, you could implement your own export provider derived from ExportProvider, which allows you to pretty much duplicate Funq's way of working:
var provider = new FunqyExportProvider();
provider.Register<IFoo>(context => new Foo());
var container = new CompositionContainer(provider);
Both instance are the same. How can I force (configure) them to be different instances?
Simply mark the SomeThing class like this:
[Export(typeof(ISomeThing)]
[PartCreationPolicy(CreationPolicy.NonShared]
public class SomeThing : ISomeThing
{
...
}
And then you will get different instances wherever you import ISomeThing.
Alternatively, you can also set a required creation policy on an import:
[Export(typeof(IFoo))]
public class Foo : IFoo
{
[Import(typeof(ISomeThing),
RequiredCreationPolicy = CreationPolicy.NonShared)]
public ISomething SomeThing { private get; set; }
}
In Glen Block's Skydrive directory linked to in Matthew Abbott's answer I found something that seems simple and lightweight: A FuncCatalog. Download it here: FuncCatalogExtension.
Using the few little classes from that project I could now do this:
var funcCatalog = new FuncCatalog();
funcCatalog.AddPart<ISomeThing>(ep => new SomeThing());
var container = new CompositionContainer(funcCatalog);
var batch = new CompositionBatch();
batch.AddExportedObject<ExportProvider>(container);
container.Compose(batch);
var a = container.GetExportedObject<ISomeThing>();
var b = container.GetExportedObject<ISomeThing>();