It is possible to retrieve host address in application service in abp framework? - asp.net

It is possible to have host address in app services?
For example we want send email to customer with specific link point to site address. How is this possible?

This came up via Google & the existing answer didn't really help. I don't necessarily agree that app services are the wrong domain for this; in ABP for example, a service is closely connected to a controller and services usually only exist in order to service web requests there. They often execute code in an authorised state that requires a signed-in user, so the whole thing is happening in the implicit domain context of an HTTP request/response cycle.
Accordingly - https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-2.2#use-httpcontext-from-custom-components
Add services.AddHttpContextAccessor(); to something like your Startup.cs - just after wherever you already call services.AddMvc().
Use dependency injection to get hold of an IHttpContextAccessor in your service - see below.
Using constructor-based dependency injection, we add a private instance variable to store the injected reference to the context accessor and a constructor parameter where the reference is provided. The example below has a constructor with just that one parameter, but in your code you probably already have a few in there - just add another parameter and set _httpContextAccessor inside the constructor along with whatever else you're already doing.
using HttpContext = Microsoft.AspNetCore.Http.HttpContext;
using IHttpContextAccessor = Microsoft.AspNetCore.Http.IHttpContextAccessor;
// ...
public class SomeService : ApplicationService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public SomeService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
}
Now service code can read the HTTP context and from there things like the HTTP request's host and port.
public async Task<string> SomeServiceMethod()
{
HttpContext context = _httpContextAccessor.HttpContext;
string domain = context.Request.Host.Host.ToLowerInvariant();
int? port = context.Request.Host.Port;
// ...
}

HttpContext.Current.Request.Url
can get you all the info on the URL. And can break down the url into its fragments.

Related

Cloud datastore dynamic namespace

Requirement
For Cloud, datastore needs to change namespace dynamically. (example store kind as per company Name)
Used Spring cloud DataRepository with Springboot for same
Issue
We need to declare spring.cloud.gcp.datastore.namespace in application.properties which is static.
Is there any way to change this dynamically with CRUDReposity of spring cloud
Thanks in advance
You can change anything you want in your application.properties at runtime using Spring Cloud Config.
Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments. The concepts on both client and server map identically to the Spring Environment and PropertySource abstractions, so they fit very well with Spring applications but can be used with any application running in any language.
Just as a quick example on how you can use this , you should firstly add the dependency : eg gradlecompile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.1.RELEASE', then you need to add the #RefreshScope on the desired configuration bean.
You will be able to view your current config at a certain endpoint, like "applicationConfig: [classpath:/application.properties]": {
"my.property": "value1",
etc
And then you can change the properties as you wish doing a POST request like :
curl -X POST http://localhost:8080 -d my.property=value2
There is also a nice article about dynamically reloading the properties in a Spring application here. It is nice because they actually display more ways that you can achieve that.
You can use DatastoreNamespaceProvider which can dynamically return needed namespace.
Was added in this PR PR
Also see this discussion here and this recommendation
#Component
#RequiredArgsConstructor
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class HeaderValueProvider implements Supplier<String>, DatastoreNamespaceProvider {
private final HttpServletRequest httpServletRequest;
#Override
public String get() {
return httpServletRequest.getHeader("someHeader");
}
}
And this
#Component
public class UserContextProvider implements DatastoreNamespaceProvider, Consumer<UUID> {
private static final ThreadLocal<UUID> USER_CONTEXT = new ThreadLocal<>();
#Override
public String get() {
return ofNullable(USER_CONTEXT.get())
.map(UUID::toString)
.orElse(null);
}
#Override
public void accept(UUID uuid) {
USER_CONTEXT.set(uuid);
}
}

How I can make private/protected API Using Web API of ASP.NET?

I want to make API(s) using ASP.NET WEB API which should be private or protected.
Using the API(s) I am planning to make Xamarin application and a MVC Website.
Only the Apps can use the API(s), otherwise if anyone get the API(s) then he/she can retrieve data using the API(s). I don't want so!
How can I do it? I need some suggestion.
You can secure you api with API Key Authentication mechanism. Here is a good tutorial
Starting go inside your global.asax.cs file and add
GlobalConfiguration.Configuration.MessageHandlers.Add(new AuthHandler())
Create a class AuthHandler in your project and make that class interface with DelegatingHandler:
public class AuthHandler: DelegatingHandler
Create two methods within your AuthHandler class called ValidateCredentials and SendAsync. The SendAsync method is overridded.
private bool ValidateCredentials(AuthenticationHeaderValue authVal){}
protected override async Task<HttpResponseMessage> SendAsync(HttpResponseMessage request, CancellationToken cancelTok){}
When a class or method has the Authorize filter applied, the MessageHandler in your global.asax is called which calls the Auth handler you created, for example:
[Authorize]
public class SomeController : ApiControler{}
So whats left is the actual authentication of the user. You need to get the header value (placed by the client application), decode it and check it against your database or whatever you use.
private bool ValidateCredentials(AuthenticationHeaderValue authVal)
{
try{
string decodedHeader = new Classes.Strings().decode(authVal);
this.user = // some query to check against database goes here
return true;
}
catch{
// some type of error control here
return false
}
}
protected override async Task<HttpResponseMessage> SendAsync(HttpResponseMessage request, CancellationToken cancelTok)
{
if(ValidateCredentials(request.Headers.Authorization))
{
// store user here to use around the api on this request
}
}
So in short HTTP needs to store your authentication header value. Use that value on each request to filter any class or function you require authentication on. Next, I would read up on http headers, specifically the Authentication header value.

Understanding about constructor in Web Api

My web api looks like:
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly ApplicationDbContext _context;
public ValuesController(ApplicationDbContext context)
{
_context = context;
}
[HttpGet]
public string Get()
{
// get random user
var user = _context.Users.SingleOrDefault();
return user?.Email ?? "";
}
}
Trying to call it via jquery:
$.get('/api/values', function (email) {
console.log(email)
})
I've 2 questions:
1/. Why didn't console.log(email) work although I was getting the response successful?
There was nothing in the Console tab.
2/. When I made a request to server (/api/values), the breakpoint had been caught:
My question: where had ValuesController been called within context? I'd sent a request from client, then the constructor was hit (I'm sure that I didn't send something like ApplicationDbContext from client to server :v)
UPDATE: By changing $.get('/api/values', {}, function (email) {} to $.get('/api/values', function (email) {}. I've fixed the first problem. It's my bad. Sorry about that.
Shorter Answer
My question: where had ValuesController been called within context? I'd sent a request from client, then the constructor was hit.
The HTTP Request arrived. ASP.NET MVC Routing told the application to use the ValuesController to handle the request. The application constructed the ValuesController, supplying an instance of ApplicationDbContext via dependency injection.
Longer Answer
The Startup.Configure method is used to specify how the ASP.NET application will respond to individual HTTP requests. Since you are using Web API, you have configured app.UseMvc(). Result: when an HTTP Request arrives, MVC Routing tells the application to use the appropriate controller.
The Startup.ConfigureServices method is used to specify services that are available via dependency injection. Since you are injecting an ApplicationDbContext into your constructor, you have configured services.AddDbContext<ApplicationDbContext>(). Result: when the application constructs a ValuesController, ASP.NET Dependency Injection will provide an instance of the ApplicationDbContext.

Spring Cloud Netflix : Passing host request parameter via RequestInterceptor to FeignClient

I am building a Spring Cloud project (Brixton.M4 with Spring Boot 1.3.1) with Eureka, Zuul and FeignClient where I am trying to add multi tenancy support (Tenants are identified by subdomain : tenant1.myservice.com). To do so, I would like to somehow pass the original subdomain along requests that are forwarded from a service to the other via Feign but I can't seem to be able to find the right way to do it.
What I have is a client that exposes a #RestController which calls a #FeignClient to communicate with my backend which exposes server operations to the client through its own #RestController.
The #FeignClient using same interface as my #RestController on the server :
#FeignClient(name = "product")
public interface ProductService extends IProductService {
}
What I am currently trying to do is set a header in a RequestInterceptor :
#Component
public class MultiTenancyRequestInterceptor implements RequestInterceptor {
private CurrentTenantProvider currentTenantProvider;
#Autowired
public MultiTenancyRequestInterceptor(CurrentTenantProvider currentTenantProvider) {
this.currentTenantProvider = currentTenantProvider;
}
#Override
public void apply(RequestTemplate template) {
try {
template.header("TENANT", currentTenantProvider.getTenant());
} catch (Exception e) {
// "oops"
}
}
}
My provider class is a simple component where I'm trying to inject a request / session scope bean :
#Component
public class CurrentTenantProvider {
#Autowired
private CurrentTenant currentTenant;
//...
}
The bean (I tried both session and request scope) :
#Bean
#Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public CurrentTenant currentTenant() {
return new CurrentTenant();
}
On the server, I use Hibernate multitenant provider that is supposed to catch the header value and use it to define which DB to connect to :
#Autowired
private HttpServletRequest httpRequest;
#Override
public String resolveCurrentTenantIdentifier() {
return httpRequest.getHeader("TENANT");
}
It seems the Feign call to the server is done in another thread and out of the incoming request scope, so i'm not sure how to pass that value along.
It all works fine when I hardcode the tenant value in the RequestInterceptor so I know the rest is working properly.
I have also looked at many other posts about Zuul "X-Forwaded-For" header and cannot find it in the request received on the server. I have also tried adding a ZuulFilter to pass host name to next request but what I see is that original request to the Client is picked up by the ZuulFilter and I can add but not when the Feign request is sent to the backend service even if I map it in zuul (i guess that is intended ?).
I am not really sure what's the next step and would appreciate some suggestions.
Hope that it's of any use for you but we're doing sth similar in Spring-Cloud-Sleuth but we're using a ThreadLocal to pass span between different libraries and approaches (including Feign + Hystrix).
Here is an example with the highlighted line where we retrieve the Span from the thread local: https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceFeignClientAutoConfiguration.java#L123

Problems integrating NServiceBus with ServiceStack IRequiresRequestContext

I am looking to integrate NServiceBus into an existing ServiceStack web host. ServiceStack is currently using the built in Funq IoC container. NServiceBus has been configured (elsewhere in the system) to use Unity for IoC.
ServiceStack has a feature whereby IRequestContext will be automatically injected when it finds the IRequiresRequestContext interface on a class. NServiceBus has a similar feature for Message Mutators, via the IMutateOutgoingTransportMessages interface.
The application is a multi-tenant application. Single application, which via an API Key, passes an account code through to the NServiceBus handler (indirectly via a provider that is called on the construction of the handler's constructor injection using Unity).
My problem arises in ServiceStack. I am using a request filter to drag the API key out of the request headers, which I look-up in a database, and then finally write into the IHttpRequest.Items collection:
appHost.RequestFilters.Add((req, res, requestDto) =>
{
var tenant = tenantRepository.GetByApiKey(
req.Items.Add("AccountCode", tenant.AccountCode);
}
I then have an NServiceBus transport message mutator, that implements that IRequiresRequestContext interface, and this class is located in the same assembly as the ServiceStack services registered in the AppHost:
public class MessageHeaderMutator : IMutateOutgoingTransportMessages, INeedInitialization, IRequiresRequestContext
{
#region IRequiresRequestContext Members
public IRequestContext RequestContext { get; set; }
#endregion
#region IMutateOutgoingTransportMessages Members
public void MutateOutgoing(object[] messages, NServiceBus.TransportMessage transportMessage)
{
transportMessage.Headers.Add("AccountCode", RequestContext.Get<IHttpRequest>().Items["AccountCode"].ToString());
}
#endregion
#region INeedInitialization Members
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<MessageHeaderMutator>(DependencyLifecycle.InstancePerCall);
}
#endregion
}
However, RequestContext is never injected, and is always null. My theory is that the two interface injections, injected via the two separate frameworks, are somehow clashing.
I have a workaround, which is to use the ServiceStack HostContext.Items instead, as per this discussion, but I am concerned that the HostContext is not a per request collection, so I might end up writing data to the wrong tenant. Workaround is:
// app host
appHost.RequestFilters.Add((req, res, requestDto) =>
{
var accountCode = tenantRepository.GetByApiKey(
HostContext.Instance.Items.Add("AccountCode", client.AccountCode);
}
// message mutator
public class MessageHeaderMutator : IMutateOutgoingTransportMessages, INeedInitialization
{
#region IMutateOutgoingTransportMessages Members
public void MutateOutgoing(object[] messages, NServiceBus.TransportMessage transportMessage)
{
var accountCode = HostContext.Instance.Items["AccountCode"].ToString();
transportMessage.Headers.Add("AccountCode", accountCode);
}
#endregion
#region INeedInitialization Members
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<MessageHeaderMutator>(DependencyLifecycle.InstancePerCall);
}
#endregion
}
My question is therefore twofold:
The first is, why does IRequiresRequestContext not correctly inject RequestContext into the Message mutator, or is there a way to inject RequestContext manually?
Is the use of the HostContext safe to assume it is per request?
Bonus question: Is the use of two separate IoC containers in the same project (Unity in NServiceBus and Funq in ServiceStack) a really bad idea? Would it be smarter to get ServiceStack to use the same Unity IoC container as NServiceBus?
P.S. This is NServiceBus 4 (beta at time of writing).
It is precisely because you're using 2 different containers that DI doesn't work for you out of the box for objects registered in different containers.
You don't necessarily need to standardize on a single container (though it would save you from dealing with these sorts of issues all the time).
What you can do to keep working with both containers is to tell the NServiceBus container how to resolve IRequiresRequestContext like this:
public class RequestContextBootstrapper : INeedInitialization
{
public void Init()
{
Configure.Component<IRequiresRequestContext>( /* get object from ServiceStack */ );
}
}
You can access the ServiceStack container via AppHostBase.Container and use it to resolve your objects as Udi suggested.

Resources