I'm not able to get this work.
I try implement the Response Pattern for Masstransit.
I'm 100% sure there is only a detail missing.
The Consumer receives my message but I get an timeout expetion on the client side.
I tried similar to the code given here: https://masstransit-project.com/usage/requests.html
Client:
public static async Task Main(string[] args)
{
var TheBus = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
sbc.Host(("rabbitmq://192.168.180.44"), host =>
{
host.Username("bsone");
host.Password("bsone");
});
});
var factory = TheBus.CreateClientFactory();
var serviceAddress = new Uri("rabbitmq://192.168.180.44/hugo");
var client = factory.CreateRequestClient<Registrieren>(TimeSpan.FromSeconds(10));
var response = client.GetResponse<IRegisterDone>( new Registrieren()
{
FaMaterial = null,
Gewicht = 1,
Erledigt = true,
UserId = "WW",
Charge = "11",
stock = null
}).Result;
Console.WriteLine(response.Message.Status);
}
}
Server
public class Program
{
private static IBusControl bus;
public static void Main(string[] args)
{
var TheBus = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
sbc.Host(("rabbitmq://192.168.180.44"), host =>
{
host.Username("bsone");
host.Password("bsone");
});
sbc.ReceiveEndpoint("hugo", end =>
{
end.Consumer<RegistrierenFaMaterialBuchungConsumer>();
});
});
TheBus.Start();
Console.WriteLine("Masstransit Up and Running");
Console.ReadLine();
}
}
public class RegistrierenFaMaterialBuchungConsumer : IConsumer<wsb.erp.net.waage.messages.bsone.IRegistrieren>
{
private IRegistrieren _registrieren;
public Task Consume(ConsumeContext<IRegistrieren> context)
{
_registrieren = context.Message;
Console.WriteLine($"{DateTime.Now} - Message Registrieren Received");
context.Respond<IRegisterDone>(new RegisterDone() { Status = "DONE" });
return Task.CompletedTask;
}
}
You need to Start the bus on the client as well, just like you're starting it on the server with the receive endpoint.
Related
I'm building a desktop APP using windows forms that needs to be authenticated via a WebAPI using Token authentication.
The API is proved that work because a mobile APP is using it and also I can get results using POSTMAN
The problem is when I'm calling the Authentication method from the desktop App.
When I do the request, the API recieves it and it only goes until ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context), not reaching GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) in the Auth process.
Here is my CustomAuthProvider
public class CustomOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "El nombre de usuario o contraseƱa son incorrectos");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");
var ticket = new AuthenticationTicket(oAuthIdentity, null);
context.Validated(ticket);
}
}
Here is my Startup class
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
HttpConfiguration httpConfig = new HttpConfiguration();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
ConfigureWebApi(httpConfig);
}
}
At the moment I'm trying two different ways to authenticate the APP.
First One:
public LoginResponseModel Authenticate(LoginRequestModel applicationUser)
{
using (var client = new WebClient())
{
try
{
client.Headers["Content-Type"] = "application/json";
var data = applicationUser.Serialize();
var response = client.UploadString(Context.ApiUrl + "Authenticate","POST", JsonConvert.SerializeObject(applicationUser));
var resultJson = JsonConvert.DeserializeObject<LoginResponseModel>(response);
return resultJson;
}
catch (Exception exception)
{
}
}
return null;
}
And second one:
public async Task<ApplicationUser> Authenticate(LoginRequestModel applicationUser)
{
var client = new HttpClient();
try
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var data = applicationUser.Serialize();
var response = await client.PostAsJsonAsync(Context.ApiUrl + "Authenticate",data );
// return null by default (test)
return null;
}
catch (Exception exception)
{
}
return null;
}
And this is the model I'm using for the request
public class LoginRequestModel
{
public string Grant_type { get; set; } = "Password";
public string UserName { get; set; }
public string Password { get; set; }
}
And this should be the response:
public class LoginResponseModel
{
public string Access_token { get; set; }
public string Token_type { get; set; }
public string Expires_in { get; set; }
}
Ah the moment both ways of calling the API only reach the initial verification of the owin process (ValidateClientAuthentication). What can be happening? How I can fix this? What I need to do to make the process go to GrantResourceOwnerCredentials?
thanks for the help
I solved my problem. The problem was that the form wasn't being filled and sent correctly.
private AuthToken GetAuthToken(LoginRequestModel applicationUser)
{
using (var client = new HttpClient())
{
var form = new Dictionary<string, string>
{
{"grant_type", "password"},
{"username", applicationUser.UserName},
{"password", applicationUser.Password},
};
try
{
var tokenResponse = client.PostAsync(Context.ApiUrl + "Authenticate", new FormUrlEncodedContent(form)).Result;
var token = tokenResponse.Content.ReadAsAsync<AuthToken>(new[] { new JsonMediaTypeFormatter() }).Result;
return token;
}
catch (Exception e)
{
Log4Net.log.Error("Error Getting Auth token", e);
return null;
}
}
}
I have been following the tutorials here to build my application. Everything works well at the authentication side. Now, the problem I am having is when I move to the resource server to retrieve data. If I place the [Authorize] on any method in the resource server I get the error message "No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin is therefore not allowed access. The response had HTTP status code 500.". If I remove it everything works fine but I am unable access any claims or roles associated with the user
Excerpts of the startup.cs code of my AuthServer is as follows
public class Startup
{
string PublicHostUri { get { return "https://localhost:44354"; } }
private readonly IHostingEnvironment _environment;
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsEnvironment("Development"))
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
_environment = env;
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration["Data:UserAccConnection:ConnectionString"];
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "reportbook.auth.pfx"), "");
var reportbookConnnectionString = Configuration["Data:ReportBookDbConnection:connectionString"];
services.AddDbContext<ReportBookDbContext>(options =>
options.UseSqlServer(reportbookConnnectionString));
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddDbContext<UserDbContext>(options =>
options.UseSqlServer(connectionString, b => b.MigrationsAssembly(migrationsAssembly)));
// Register the Identity services.
services.AddIdentity<ApplicationUser, UserRole>()
.AddEntityFrameworkStores<UserDbContext, Guid>()
.AddDefaultTokenProviders();
services.AddCors();
services.AddMvc();
services.AddIdentityServer()
.AddDefaultEndpoints()
.AddOperationalStore(builder =>
builder.UseSqlServer(connectionString,
options => options.MigrationsAssembly(migrationsAssembly)))
.AddConfigurationStore(builder =>
builder.UseSqlServer(connectionString,
options => options.MigrationsAssembly(migrationsAssembly)))
.SetSigningCredential(cert)
.AddAspNetIdentity<ApplicationUser>()
.AddProfileService<IdentityWithAdditionalClaimsProfileService>();
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
});
services.AddTransient<IProfileService, IdentityWithAdditionalClaimsProfileService>();
services.AddTransient<IUnitOfWorkAsync, UnitOfWork>();
services.AddScoped<IDataContextAsync, ReportBookDbContext>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
InitializeDbTestData(app);
}else
{
app.UseExceptionHandler(
builder =>
{
builder.Run(
async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
}
});
});
}
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseStaticFiles();
app.UseCors(builder =>
builder.AllowAnyOrigin()
.AllowCredentials()
.AllowAnyHeader()
.AllowAnyMethod());
app.UseCsp(options => options.DefaultSources(directive => directive.Self())
.ImageSources(directive => directive.Self()
.CustomSources("*"))
.ScriptSources(directive => directive.Self()
.UnsafeInline())
.StyleSources(directive => directive.Self()
.UnsafeInline()));
app.UseXContentTypeOptions();
app.UseXfo(options => options.Deny());
app.UseXXssProtection(options => options.EnabledWithBlockMode());
app.UseIdentity();
app.UseIdentityServer();
//app.UseMvc(routes =>
//{
// routes.MapRoute(
// name: "default",
// template: "{controller=Home}/{action=Index}/{id?}");
//});
app.UseMvcWithDefaultRoute();
app.UseMvc();
//databaseInitializer.Seed(app).GetAwaiter().GetResult();
}
private static void InitializeDbTestData(IApplicationBuilder app)
{
using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
scope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>().Database.Migrate();
scope.ServiceProvider.GetRequiredService<UserDbContext>().Database.Migrate();
var context = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
if (!context.Clients.Any())
{
foreach (var client in Clients.Get())
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.Scopes.Any())
{
foreach (var clientSope in Scopes.Get())
{
context.Scopes.Add(clientSope.ToEntity());
}
context.SaveChanges();
}
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<UserRole>>();
if (!userManager.Users.Any())
{
foreach (var newUser in Users.Get())
{
ApplicationUser user = new ApplicationUser();
user.Id = new Guid();
user.EmailConfirmed = true;
user.UserName = newUser.Email;
user.UserNo = newUser.UserNo;
user.FirstName = newUser.FirstName;
user.LastName = newUser.LastName;
user.Gender = newUser.Gender;
user.UserCategory = newUser.UserCategory;
user.ZoneInfo = newUser.ZoneInfo;
userManager.CreateAsync(user, "Password123!").Wait();
userManager.AddClaimAsync(user, new Claim("UserCategory", user.UserCategory)).Wait();
foreach (var role in newUser.UserRoles)
{
if (!roleManager.RoleExistsAsync(role).GetAwaiter().GetResult())
{
UserRole userRole = new UserRole();
userRole.Id = new Guid();
userRole.Name = role;
roleManager.CreateAsync(userRole).Wait();
}
userManager.AddToRoleAsync(user, role).Wait();
userManager.AddClaimAsync(user, new Claim(JwtClaimTypes.Role, role)).Wait();
}
}
}
}
}
}
Excerpts of startup.cs file of the resource server is as follows
public class Startup
{
private IHostingEnvironment _env { get; set; }
public Startup(IHostingEnvironment env)
{
_env = env;
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsEnvironment("Development"))
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
//private static void InitializeDbTestData(IApplicationBuilder app)
//{
// using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
// {
// scope.ServiceProvider.GetRequiredService<ReportBookDbContext>().Database.Migrate();
// }
//}
// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
var folderForKeyStore = Configuration["Data:keystore:KeyStoreFolderWhichIsBacked"];
var cert = new X509Certificate2(Path.Combine(_env.ContentRootPath, "reportbook.auth.pfx"), "");
services.AddDataProtection()
.SetApplicationName("ReportBook")
.ProtectKeysWithDpapiNG("CERTIFICATE=Hashid:" + cert.Thumbprint,flags: DpapiNGProtectionDescriptorFlags.None);
services.AddDbContext<ReportBookDbContext>(options =>
options.UseSqlServer(Configuration["Data:ReportBookDbConnection:connectionString"],
b => b.MigrationsAssembly("ReportBook.Resource")));
// Add framework services.
services.AddCors();
services.AddApplicationInsightsTelemetry(Configuration);
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseDeveloperExceptionPage();
app.UseStatusCodePagesWithReExecute("/error");
if (env.IsDevelopment())
{
//InitializeDbTestData(app);
}
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
IdentityServerAuthenticationOptions identityServerValidationOptions = new IdentityServerAuthenticationOptions
{
Authority = "https://localhost:44354/",
ScopeName = "resource_server",
ScopeSecret = new IdentityServer4.Models.Secret("scopeSecret".Sha256()).ToString(),
AutomaticAuthenticate = true,
SupportedTokens = SupportedTokens.Both,
AutomaticChallenge = true
};
app.UseIdentityServerAuthentication(identityServerValidationOptions);
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseExceptionHandler(
builder =>
{
builder.Run(
async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
}
});
});
app.UseCors(builder =>
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
app.UseMvc();
}
}
Below is the an excerpt of the the controller whose method I am trying to reach
[HttpGet("GetInstitutions")]
//[Authorize]
public IActionResult GetInstitutions([FromQuery]InstitutionSearchQry model)
{
var authorisation = Request.Headers["Authorization"];
bool auth = User.Identity.IsAuthenticated;
IEnumerable<Institution> _institutions = null;
string userCategory = User.Claims.Where(a => a.Type == "UserCategory").Select(a => a.Value).FirstOrDefault().ToString();
string zoneInfo = User.Claims.Where(a => a.Type == "ZoneInfo").Select(a => a.Value).FirstOrDefault().ToString();
string userNo = User.Claims.Where(a => a.Type == "UserNo").Select(a => a.Value).FirstOrDefault().ToString();
bool admin = User.IsInRole("Admin");
List<Student> students = new List<Student>();
//Institution institution = _institutionService.Find(a => a.InstitutionID == zoneInfo);
var pagination = Request.Headers["Pagination"];
if (!string.IsNullOrEmpty(pagination))
{
string[] vals = pagination.ToString().Split(',');
int.TryParse(vals[0], out page);
int.TryParse(vals[1], out pageSize);
}
switch (userCategory)
{
case "Guardian":
{
students = _guardianService.GetStudents(userNo).ToList();
_institutions = _admissionService.GetInstitutions(students.Select(a => a.StudentID).ToList(),model.StartYear,model.EndYear, s => s.Term.AcademicYear.Institution.UniversityInstitutes.Select(a => a.University));
}
break;
case "Student":
{
_institutions = _admissionService.GetInstitution(userNo,s=>s.Term.AcademicYear.Institution.UniversityInstitutes.Select(a=>a.University));
}
break;
default:
{
_institutions = _institutionService.GetInstitutions(a => a.AdministrativeStructure.ZoneInfo == zoneInfo && a.Level.LevelName==model.Level, page, pageSize, out totalCount, s => s.AdministrativeStructure, s => s.Level,s=>s.UniversityInstitutes.Select(a=>a.University));
}
break;
}
if (!String.IsNullOrEmpty(model.Level) && model.Level != "myschool")
{
_institutions = _institutions.Where(a => a.Level.LevelName == model.Level);
}
var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
Response.AddPagination(page, pageSize, totalCount,totalPages);
Response.AddIdentityInfo(userCategory, admin, userNo, zoneInfo);
IEnumerable<InstitutionDataViewModel> _instDataModel = Mapper.Map<IEnumerable<Institution>, IEnumerable<InstitutionDataViewModel>>(_institutions);
return new OkObjectResult(_instDataModel);
}
The following is the angular 2 code from where the call is made to the resource server
#Injectable()
export class InstitutionService {
private resourceApiUrl: string;
private headers: Headers;
private storage: any;
private actionUrl: string;
public totalItems: number;
constructor(private _http: Http,
private itemsService: ItemsService,
private _configuration: Configuration,
private _router: Router,
private _authService: AuthService) {
this.resourceApiUrl = `${_configuration.resourceServer}api/Institution/`;
}
private SetHeaders(page?: number, itemsPerPage?: number) {
this.headers = new Headers();
this.headers.append('Content-Type', 'application/json');
this.headers.append('Accept', 'application/json');
if (page != null && itemsPerPage != null) {
this.headers.append('Pagination', page + ',' + itemsPerPage);
}
var token = this._authService.GetToken();
if (token !== "") {
let tokenValue = 'Bearer ' + token;
console.log("tokenValue:" + tokenValue);
this.headers.append('Authorization', tokenValue);
}
}
public GetInstitutions = (InstitutionSearchQry?: any, page?: number, itemsPerPage?: number): Observable<PaginatedResult<IInstitution[]>> => {
this.SetHeaders(page, itemsPerPage);
var paginatedResult: PaginatedResult<IInstitution[]> = new PaginatedResult<IInstitution[]>();
let options = new RequestOptions({ headers: this.headers, body: '' });
if (!InstitutionSearchQry.level) {
this.actionUrl = "GetInstitutions";
} else {
this.actionUrl = "GetInstitutions/", InstitutionSearchQry;
}
return this._http.get(this.resourceApiUrl + this.actionUrl, options)
.map((res: Response) => {
//console.log(res.headers.keys());
paginatedResult.result = res.json();
if (res.headers.get("Pagination") != null) {
//var pagination = JSON.parse(res.headers.get("Pagination"));
var paginationHeader: Pagination = this.itemsService.getSerialized<Pagination>(JSON.parse(res.headers.get("Pagination")));
paginatedResult.pagination = paginationHeader;
}
if (res.headers.get("IdentityInfo") != null) {
var identityInfo: IdentityInfo = this.itemsService.getSerialized<IdentityInfo>(JSON.parse(res.headers.get("IdentityInfo")));
paginatedResult.identityInfo = identityInfo;
}
this.totalItems = paginatedResult.pagination.TotalItems;
return paginatedResult;
}).catch(this.handleError);
};
}
So basically the authorisation information provided at the AuthServer side is not reaching the resource server.
As one can see I have added the 'CORS' service in both files.
Use this plugin for chrome browser. get from here
I have searched through all the tutorials and did exactly as explained there, but I can't reach my controller.
Here is my websocket xml config:
<websocket:handlers>
<websocket:mapping path="/updateHandler" handler="updateHandler"/>
<websocket:sockjs/>
</websocket:handlers>
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/update">
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic"/>
</websocket:message-broker>
I don't actually know do I need the handler, but without it stomp connection fails with "whoops! Lost connection to undefined".
Any suggestion in this direction is also welcome.
Here is my empty handler:
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class UpdateHandler extends TextWebSocketHandler {
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
}
}
And my controller
#RestController
public class WebSocketController {
#MessageMapping("/update")
#SendTo("/topic/messages")
public OutputMessage sendmMessage(Message message) {
return new OutputMessage(message, new Date());
}
}
I am using ngStomp from angular as suggested:
var message = {message: 'message body', id: 1};
$scope.testWebSocket = function () {
$stomp.setDebug(function (args) {
console.log(args + '\n');
});
$stomp.connect('/myAppContext/update', {})
.then(function (frame) {
var connected = true;
var subscription = $stomp.subscribe('/topic/messages', function (payload, headers, res) {
$scope.payload = payload;
}, {});
$stomp.send('/myAppContext/app/update', message);
subscription.unsubscribe();
$stomp.disconnect(function () {
console.error('disconnected');
});
}, function(error){
console.error(error);
});
};
My Message Class:
public class Message {
private String message;
private int id;
public Message() {
}
public Message(int id, String text) {
this.id = id;
this.message = text;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
My OutputMessage class:
public class OutputMessage extends Message {
private Date time;
public OutputMessage(Message original, Date time) {
super(original.getId(), original.getMessage());
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
when I execute the testWebSocket() I get following output:
Opening Web Socket...
Web Socket Opened...
>>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
<<< CONNECTED
version:1.1
heart-beat:0,0
user-name:user#domain.com
connected to server undefined
>>> SUBSCRIBE
id:sub-0
destination:/topic/messages
>>> SEND
destination:/myAppContext/app/update
content-length:33
{"message":"message body","id":1}
Why connected to server undefined?
And why my controller never gets executed after sending a message?
I am using spring-4.1.4 with security-core-3.2.5 and Tomcat server 8.0.18
As a non-pretty workaround, I moved websocket configuration to the Java config and it works.
Config below:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/update")
.withSockJS();
}
I actually don't know why.
I am using Play 2.0.4 and I'm doing a test unit for actors who make use of the database.
The test begins well, but then at a given moment the connection with the database is closed and the actor who is running fails.
Code:
public class ActorTest extends Helpers {
private FakeApplication app;
private ActorSystem actorSystem;
private ActorRef actorRef;
private BankAccount account;
#Before
public void initTest() {
Map<String, String> params = new HashMap<String, String>();
params.put("db.default.driver", "com.mysql.jdbc.Driver");
params.put("db.default.url", "mysql://root:XXXX#localhost/YYY");
params.put("ebean.default", "models.*");
app = fakeApplication(params);
actorSystem = play.api.libs.concurrent.Akka.system(app.getWrappedApplication());
}
#Test
public void updateAccountTransaction() {
running(app, new Runnable() {
#Override
public void run() {
account = BankAccount.find.byId(new Long(1));
actorRef = actorSystem.actorOf(new Props(new UntypedActorFactory() {
#Override
public UntypedActor create() {
return new AccountTaskActor(account);
}
}));
Calendar fromDate = Calendar.getInstance();
....
....
Calendar toDate = Calendar.getInstance();
final InputRangeDateMessage param = new InputRangeDateMessage(fromDate, toDate);
junit.framework.Assert.assertNotNull(account);
Future<Object> future = Patterns.ask(actorRef, param, 1000000);
Promise<Object> sdf = Akka.asPromise(future);
Promise<Result> r2 = sdf.map(new Function<Object, Result>() {
#Override
public Result apply(Object response) throws Throwable {
if (response instanceof ErrorMessage) {
ErrorMessage e = (ErrorMessage) response;
System.out.println("Error Message " + e.getErrorText());
junit.framework.Assert.assertEquals(e.getErrorCode(), -1);
} else if (response instanceof BankAccountMessage) {
BankAccount a = ((BankAccountMessage) response).getAccount();
System.out.println("BankAccount " + a.accountsLastUpdate);
}
return ok();
}
});
Result test2;
test2 = async(r2);
}
});
}
}
AFAIK, you have to wait for the end of your Promise:
...
Result test2 = r2.get();
In my Mainpage.xaml.cs file I have a function that creates an instance of another class and tries to download a webpage using a HttpWebRequest from that instance. The problem is, once I've managed to download the webpage I can't send it back to the main UI thread. I've tried using Deployment.Current.Dispatcher.BeginInvoke to send the webpage back to a TextBlock I have waiting, but when I try I get an error telling me that I can't access the TextBlock from the other class. Is there any way to pass data between two threads without using LocalStorage?
EDIT: code below:
MainPage:
private void button1_Click(object sender, RoutedEventArgs e)
{
Member m = new Member(name, id);
}
Member class:
public Member(String Member, String API)
{
APIKey = API;
MemberName = Member;
this.super = super;
DoSend(method, string, "", null);
}
public void DoSend(string method, string url, string body, string mimetype)
{
if (WebRequest.RegisterPrefix("https://",System.Net.Browser.WebRequestCreator.ClientHttp)) {
HttpWebRequest request = WebRequest.Create(makeURI(url)) as HttpWebRequest;
request.Method = method;
request.Headers["X-NFSN-Authentication"] = MakeAuthHeader(url,body);
if (body != "")
{
byte[] bodyData = Encoding.UTF8.GetBytes(body);
request.ContentType = mimetype;
//Stuff Should Happen Here
}
else
doStuff(request);
}
public void doStuff(HttpWebRequest httpReq)
{
httpReq.BeginGetResponse(r =>
{
var httpRequest = (HttpWebRequest)r.AsyncState;
var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);
using (var reader = new StreamReader(httpResponse.GetResponseStream()))
{
var response = reader.ReadToEnd();
ResponseBlock.Text = response; //Invalid cross-thread reference
}
}, httpReq);
}
MainPage:
customClass.DownloadPage((result) =>
{
textBlock.Text = result;
},
(exception) =>
{
MessageBox.Show(exception.Message);
});
CustomClass:
public void DownloadPage(Action<string> callback, Action<Exception> exception)
{
WebClient webClient = new WebClient();
webClient.DonwloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
callback(e.Result);
});
}
else
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
exception(e.Error);
});
}
};
webClient.DonwloadStringAsync();
}