I upgraded my app to MvvmCross version 6.0. Now it get's to the splash screen and does nothing else. I can see the the Services are starting up by looking at the console. Here is my app.cs:
public class App : MvxApplication
{
public override void Initialize()
{
MPS.ApplicationName = Settings.ApplicationName;
EventLog.ApplicationName = Settings.ApplicationName;
BlobCache.ApplicationName = Settings.ApplicationName;
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
CreatableTypes()
.EndingWith("Singleton")
.AsInterfaces()
.RegisterAsSingleton();
//RegisterAppStart(new CustomAppStart());
//RegisterNavigationServiceAppStart<LoginViewModel>();
RegisterAppStart<LoginViewModel>();
}
}
It is pretty basic. I had converted to the new navigation system hence the RegisterNavigationServiceAppStart. That would no longer resolve so I went back to a straight RegisterAppStart. The splash screen comes up and then it stops. In case it matters, splashscreen.cs is as follows:
[Activity(
Label = "#string/ApplicationName"
, MainLauncher = true
, Icon = "#drawable/icon"
, Theme = "#style/Theme.Splash"
, NoHistory = true)]
//, ScreenOrientation = ScreenOrientation.Landscape)]
public class SplashScreen : MvxSplashScreenActivity
{
public SplashScreen()
: base(Resource.Layout.SplashScreen)
{
}
}
It's pretty vanilla, but I know things have changed along the way. My setup.cs is as follows:
public class Setup : MvxAndroidSetup
{
//public Setup(Context applicationContext)
// : base(applicationContext)
//{
//}
protected override IMvxApplication CreateApp()
{
return new App();
}
//protected override IMvxTrace CreateDebugTrace()
//{
// return new DebugTrace();
//}
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
return new MvxAppCompatViewPresenter(AndroidViewAssemblies);
}
protected override void FillValueConverters(IMvxValueConverterRegistry registry)
{
base.FillValueConverters(registry);
registry.AddOrOverwrite("DateToStringConverter", new DateToStringConverter());
registry.AddOrOverwrite("FloatToStringConverter", new FloatToStringConverter());
registry.AddOrOverwrite("DecimalToStringConverter", new DecimalToStringConverter());
registry.AddOrOverwrite("BoolToViewStatesConverter", new BoolToViewStatesValueConverter());
registry.AddOrOverwrite("ShipmentToOriginConverter", new ShipmentToOriginConverter());
registry.AddOrOverwrite("ShipmentToDestinationConverter", new ShipmentToDestinationConverter());
//registry.AddOrOverwrite("CustomName2", new AnotherVerySpecialValueConverter("Summer"));
}
protected override void FillTargetFactories(MvvmCross.Binding.Bindings.Target.Construction.IMvxTargetBindingFactoryRegistry registry)
{
base.FillTargetFactories(registry);
registry.RegisterCustomBindingFactory<EditText>("FocusText",
textView => new MvxEditTextFocusBinding(textView));
registry.RegisterCustomBindingFactory<TextView>("FocusChange",
textView => new MvxTextViewFocusChangeBinding(textView));
//registry.RegisterCustomBindingFactory<MvxSpinner>("ItemSelected",
// spinner => new MvxSpinnerItemSelectedBinding(spinner));
}
protected override IEnumerable<Assembly> AndroidViewAssemblies => new List<Assembly>(base.AndroidViewAssemblies)
{
typeof(MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView).Assembly
};
}
The only change I made to it was to remove the constructor. Per the documentation for version 6.0, the constructor no longer has parameters so I saw no reason to call it. Can anyone help?
** Update **
I added a MainApplication.cs as follows:
[Application]
public class MainApplication : MvxAppCompatApplication<Setup, App>
{
public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
}
This got me past the splash screen, but hung up on the Initialize of the LoginViewModel.
* Logs *
Maybe this will help. Here are the event log entries:
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Primary start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: FirstChance start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: PlatformServices start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: MvvmCross settings start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Singleton Cache start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: ViewDispatcher start
2018-04-17 12:17:06 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Bootstrap actions
2018-04-17 12:17:07 [TRACE] (MvvmCross.Logging.MvxLog) No view model type finder available - assuming we are looking for a splash screen - returning null
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: StringToTypeParser start
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: CommandHelper start
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: PluginManagerFramework start
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Create App
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: NavigationService
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Load navigation routes
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: App start
2018-04-17 12:17:07 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Application Initialize - On background thread
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: ViewModelTypeFinder start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: ViewsContainer start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Views start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: CommandCollectionBuilder start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: NavigationSerializer start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: InpcInterception start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: InpcInterception start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: LastChance start
2018-04-17 12:17:08 [TRACE] (MvvmCross.Core.MvxSetup) Setup: Secondary end
2018-04-17 12:17:08 [TRACE] (MvvmCross.Logging.MvxLog) AppStart: Application Startup - On UI thread
I traced it a little further. It is hanging up on the Initialize() in the view model. I created a test to demonstrate:
public class FirstViewModel : MvxViewModel
{
public FirstViewModel()
{
Task.Run(async () =>
{
var l = await ListDataSource.GetLocations();
var m = l;
});
}
public async override Task Initialize()
{
await base.Initialize();
var l = await ListDataSource.GetLocations();
var m = l;
}
}
If I set a break point on the two var m = l, It will get to the one in the constructor but will never get to the one in the Initialize. GetLocations is:
public async static Task<LocationList> GetLocations()
{
ListServiceClient client = NewClient();
LocationList ret = null;
bool TryCache = false;
try
{
//ret = await client.GetLocationListAsync();
ret = await Task<LocationList>.Factory.FromAsync((asyncCallback, asyncState) => client.BeginGetLocationList(asyncCallback, asyncState),
(asyncResult) => client.EndGetLocationList(asyncResult), null);
client.Close();
await BlobCache.LocalMachine.InsertObject("Locations", ret, DateTimeOffset.Now.AddDays(Settings.CacheDays));
}
catch (TimeoutException ex)
{
client.Abort();
EventLog.Error(ex.ToString());
TryCache = true;
}
catch (CommunicationException ex)
{
client.Abort();
EventLog.Error(ex.ToString());
TryCache = true;
}
catch (Exception ex)
{
EventLog.Error(ex.ToString());
TryCache = true;
}
if (TryCache)
{
try
{
ret = await BlobCache.LocalMachine.GetObject<LocationList>("Locations");
}
catch (KeyNotFoundException)
{
ret = null;
}
}
return ret;
}
If you set a break point on Client.Close(), it will get there if called from the constructor but not if its called from Initialize.
My problem was twofold. First, when you upgrade to version 6.0 using Android, you now have to include a MainApplication.cs as follows:
[Application]
public class MainApplication : MvxAppCompatApplication<Setup, App>
{
public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
}
Without this, you will get stuck on the SplashScreen. Secondly, you need to know that the Initialize in the first ViewModel that you display has to be synchronous. As #Ale_lipa mentioned, an MvvmCross Author wrote a blog post explaining why this is and what to do about it.
https://nicksnettravels.builttoroam.com/post/2018/04/19/MvvmCross-Initialize-method-on-the-first-view-model.aspx
In a nutshell, if you are using a SplashScreen and you really need the Initialize for your first ViewModel to be Async, you can add a CustomAppStart as follows:
public class CustomMvxAppStart<TViewModel> : MvxAppStart<TViewModel>
where TViewModel : IMvxViewModel
{
public CustomMvxAppStart(IMvxApplication application, IMvxNavigationService navigationService) : base(application, navigationService)
{
}
protected override void NavigateToFirstViewModel(object hint)
{
NavigationService.Navigate<TViewModel>();
}
}
In you App.cs, replace your:
RegisterAppStart<FirstViewModel>();
with:
RegisterCustomAppStart<CustomMvxAppStart<FirstViewModel>>();
This will allow your first Initialize to be async. I am only sure it works for Android and only if you are using a SplashScreen.
I am quite clear, that this is not the issue related to the code from this question, but it's directly related to upgrade to MvvmCross 6.0 I've bumped into.
Just adding this as it might help someone to save a few hours as this thing not mentioned in official documentation reg. upgrading as of now.
So, in my case it was an issue with overloaded methods in Setup class:
public override IEnumerable<Assembly> GetViewAssemblies()
{
var list = new List<Assembly>();
list.AddRange(base.GetViewAssemblies());
list.Add(typeof(App).GetTypeInfo().Assembly);
return list;
}
public override IEnumerable<Assembly> GetViewModelAssemblies()
{
var list = new List<Assembly>();
list.AddRange(base.GetViewModelAssemblies());
list.Add(typeof(CoreApp).GetTypeInfo().Assembly);
return list;
}
I needed that as my Views and ViewModel are located in separate projects. After the upgrade the app wasn't running further than initialization, without any errors. After removing those everything started working fine. (Apparently, the newest version handles that automatically).
For everyone benefit, Jim created a bug in MvvmCross GitHub repo. One of the MvvmCross project contributors provided a workaround for his problem and blogged about it.
Further to Jim's post, I have a SplashScreen and my startup view model depends on whether this is a first activation or not and the decion about it is made in Core project's AppStart.Startup() method.
My app seems to be working right now and at a high level, the key classes look like this:
Core.App
public class App : MvxApplication
{
public override void Initialize()
{
// IoC registrations here
RegisterAppStart(new AppStart(this));
}
}
Core.AppStart
public class AppStart : MvxAppStart
{
public AppStart(IMvxApplication application) : base(application)
{
}
protected override async void Startup(object hint = null)
{
base.Startup(hint);
// logic to navigate to intro viewmodel or home viewmodel
}
}
Droid.Setup
public class Setup : MvxAppCompatSetup<App>
{
protected override IMvxApplication CreateApp()
{
return new Core.App();
}
protected override void InitializeIoC()
{
base.InitializeIoC();
// Custom IoC initialization
}
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
return new MvxAppCompatViewPresenter(AndroidViewAssemblies);
}
protected override IEnumerable<Assembly> AndroidViewAssemblies => new List<Assembly>(base.AndroidViewAssemblies)
{
typeof(NavigationView).Assembly,
typeof(FloatingActionButton).Assembly,
typeof(Android.Support.V7.Widget.Toolbar).Assembly,
typeof(Android.Support.V4.Widget.DrawerLayout).Assembly,
typeof(Android.Support.V4.View.ViewPager).Assembly,
};
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
MvxAppCompatSetupHelper.FillTargetFactories(registry);
base.FillTargetFactories(registry);
}
}
Related
Im trying to perform a synchronization task without blocking UI thread. I have implemented a Android Service to do so, but I found out, if the synchronization task needs too much computational time, the UI thread was blocked. So I tried the migration to IntentService. This is how my IntentService looks like:
[Service]
public class SynchronizeIntentService : IntentService
{
static readonly string TAG = typeof(SynchronizeIntentService).FullName;
private NotificationCompat.Builder Builder;
private NotificationManagerCompat NotificationManager;
public SynchronizeIntentService() : base("SynchronizeIntentService")
{
}
public override void OnDestroy()
{
var tmp = 5;
base.OnDestroy();
}
private NotificationChannel createNotificationChannel()
{
var channelId = Constants.NOTIFICATION_CHANNELID;
var channelName = "My Notification Service";
var Channel = new NotificationChannel(channelId, channelName, Android.App.NotificationImportance.Default);
Channel.LightColor = Android.Resource.Color.HoloBlueBright;
Channel.LockscreenVisibility = NotificationVisibility.Public;
return Channel;
}
private void createForegroundService()
{
var mNotificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
mNotificationManager.CreateNotificationChannel(createNotificationChannel());
}
var notificationBuilder = new NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNELID);
GenerateNotification();
StartForeground(Constants.SERVICE_RUNNING_NOTIFICATION_ID, Builder.Notification);
}
private void GenerateNotification()
{
NotificationManager = NotificationManagerCompat.From(this);
Builder = new NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNELID);
Builder.SetContentTitle(ContaScan.Classes.Localize.GetString("Global_SynchProcess", ""))
.SetSmallIcon(Resource.Drawable.icon)
.SetPriority(NotificationCompat.PriorityLow);
}
protected async override void OnHandleIntent(Intent intent)
{
Log.Debug(TAG, "Service Started!");
await Synch();
Log.Debug(TAG, "Service Stopping!");
StopForeground(true);
this.StopSelf();
}
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
base.OnStartCommand(intent, flags, startId);
createForegroundService();
return StartCommandResult.Sticky;
}
private async Task Synch()
{
//Large synch process
}
}
And this is how the service is getting started:
startServiceIntent = new Intent(Android.App.Application.Context, typeof(SynchronizeIntentService));
startServiceIntent.SetAction(Constants.ACTION_START_SERVICE);
ContextWrapper contextWrapper = new ContextWrapper(Android.App.Application.Context);
contextWrapper.StartService(startServiceIntent);
The problem is OnDestroy() method is called while the Synch() task is being performed and looks like the IntentService is being killed before ending the process.
What am I doing wrong?
First, check your API level. This class was deprecated in API level 30.
And then, when you use the OnHandleIntent, do not call Service.stopSelf().
This method is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call Service.stopSelf().
For more details, please check the link below. https://developer.android.com/reference/android/app/IntentService#onHandleIntent(android.content.Intent)
We are using spring-security 5.2 for securing our REST API through JWT validation.
With the spring:security:oauth2:resourceserver:jwt:jwk-set-uri property we indicate the remote JWKS endpoint which
translates into Spring creating a NimbusJwtDecoder based on this URI.
Further down, a RemoteJWKSet object is created that caches the calls to the JWKS endpoint with a default TTL to 5 minutes.
Is there a way to increase this TTL to minimise the remote calls ?
Maybe injecting a new DefaultJWKSetCache instance somewhere with a different TTL ?
It seems safe to keep this in cache for as long as possible because when we receive a token with an unknown kid, the call to the JWKS endpoint will be resumed to update the key set.
The call stack for retrieving the key is bellow
JwtAuthenticationProvider
public Authentication authenticate(Authentication authentication)
...
jwt = this.jwtDecoder.decode(bearer.getToken())
...
o.s.security.oauth2.jwt.NimbusJwtDecoder
public Jwt decode(String token)
...
Jwt createdJwt = createJwt(token, jwt);
...
private Jwt createJwt(String token, JWT parsedJwt)
...
JWTClaimsSet jwtClaimsSet = this.jwtProcessor.process(parsedJwt, null);
....
DefaultJWTProcessor
public JWTClaimsSet process(final JWT jwt, final C context)
...
if (jwt instanceof SignedJWT) {
return process((SignedJWT)jwt, context);
}
...
public JWTClaimsSet process(final SignedJWT signedJWT, final C context)
...
List<? extends Key> keyCandidates = selectKeys(signedJWT.getHeader(), claimsSet, context);
...
private List<? extends Key> selectKeys(final JWSHeader header, final JWTClaimsSet claimsSet, final C context)
....
if (getJWSKeySelector() != null) {
return getJWSKeySelector().selectJWSKeys(header, context);
}
....
JWSVerificationKeySelector
public List<Key> selectJWSKeys(final JWSHeader jwsHeader, final C context)
...
List<JWK> jwkMatches = getJWKSource().get(new JWKSelector(jwkMatcher), context);
...
RemoteJWKSet
public List<JWK> get(final JWKSelector jwkSelector, final C context)
...
JWKSet jwkSet = jwkSetCache.get();
if (jwkSet == null) {
jwkSet = updateJWKSetFromURL();
}
...
DefaultJWKSetCache
public JWKSet get() {
if (isExpired()) {
jwkSet = null; // clear
}
return jwkSet;
}
Security dependencies:
+- org.springframework.boot:spring-boot-starter-security:jar:2.2.4.RELEASE:compile
| +- org.springframework.security:spring-security-config:jar:5.2.1.RELEASE:compile
| \- org.springframework.security:spring-security-web:jar:5.2.1.RELEASE:compile
+- org.springframework.security:spring-security-oauth2-jose:jar:5.2.2.RELEASE:compile
| +- org.springframework.security:spring-security-core:jar:5.2.1.RELEASE:compile
| \- org.springframework.security:spring-security-oauth2-core:jar:5.2.1.RELEASE:compile
+- com.nimbusds:nimbus-jose-jwt:jar:8.8:compile
| +- com.github.stephenc.jcip:jcip-annotations:jar:1.0-1:compile
| \- net.minidev:json-smart:jar:2.3:compile (version selected from constraint [1.3.1,2.3])
| \- net.minidev:accessors-smart:jar:1.2:compile
| \- org.ow2.asm:asm:jar:5.0.4:compile
+- org.springframework.security:spring-security-oauth2-resource-server:jar:5.2.1.RELEASE:compile
Looks like I'm a bit late to the party, but I was the one to implement this feature for 5.4 release and now you're able to configure it with Spring Cache:
var jwkSetCache = new ConcurrentMapCache("jwkSetCache", CacheBuilder.newBuilder()
// can set the value here or better populate from properties
.expireAfterWrite(Duration.ofMinutes(30))
.build().asMap(), false);
var decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
.restOperations(restOperations)
.cache(jwkSetCache)
.build();
I ended up doing the following:
#Bean
public JwtDecoder jwtDecoder() {
JWSKeySelector<SecurityContext> jwsKeySelector = null;
try {
URL jwksUrl = new URL("https://localhost/.well-known/openid-configuration/jwks");
long cacheLifespan = 500;
long refreshTime = 400;
JWKSetCache jwkSetCache = new DefaultJWKSetCache(cacheLifespan, refreshTime, TimeUnit.MINUTES);
RemoteJWKSet<SecurityContext> jwkSet = new RemoteJWKSet<>(jwksUrl,null,jwkSetCache);
jwsKeySelector = JWSAlgorithmFamilyJWSKeySelector.fromJWKSource(jwkSet);
}
catch (KeySourceException e) {
e.printStackTrace();
}
catch (MalformedURLException e) {
e.printStackTrace();
}
DefaultJWTProcessor<SecurityContext> jwtProcessor = new DefaultJWTProcessor<>();
jwtProcessor.setJWSKeySelector(jwsKeySelector);
return new NimbusJwtDecoder(jwtProcessor);
}
Spring Security 5.4 allows to pass a cache to the decoderbuilder method. So you can pass your own cache and nimbusjwtdecoder will use that cache to get value.
For clearing cache u can have a scheduler job in your configuration.
#Scheduled(fixedRateString = "5000")
public void clearCachesAfterEvictionTime() {
Optional.ofNullable(cacheManager().getCache("JWKSetCache")).ifPresent(Cache::clear);
}
Hope it helps.
Nimbus allows two ways to override default HTTP connect and read timeouts
By passing a configured ResourceRetriever, for example:
int httpConnectTimeoutMs = 5_000;
int httpReadTimeoutMs = 5_000;
int httpSizeLimitBytes = 100_000;
JWKSource<?> jwkSource = new RemoteJWKSet<>(
new URL("https://demo.c2id.com/jwks.json"),
new DefaultResourceRetriever(
httpConnectTimeoutMs, httpReadTimeoutMs, httpSizeLimitBytes
)
);
By setting the following Java system properties (suitable when there
is no direct way to construct the RemoteJWKSet, can occur in
frameworks that use this library internally):
Setting a HTTP connect timeout of 5 seconds:
com.nimbusds.jose.jwk.source.RemoteJWKSet.defaultHttpConnectTimeout=5000
Setting a HTTP read timeout of 2.5 seconds:
com.nimbusds.jose.jwk.source.RemoteJWKSet.defaultHttpReadTimeout=2500
Refer to https://connect2id.com/products/nimbus-jose-jwt/examples/validating-jwt-access-tokens#remote-jwk-set-timeouts for more details
I'm using Spring-AMQP-rabbit in one of applications which acts as a message-consumer. The queues are created and subscribed to the exchange at startup.
My problem:
When the RabbitMq server is restarted or removed and added completely, the Queue's are not recreated. The connection to the RabbitMq server is re-stored, but not the Queues.
I've tried to do the queue admin within a ConnectionListener but that hangs on startup. I guess the admin is connection aware and should do queue management upon connection restore isn't?
My Queues are created by a service:
#Lazy
#Service
public class AMQPEventSubscriber implements EventSubscriber {
private final ConnectionFactory mConnectionFactory;
private final AmqpAdmin mAmqpAdmin;
#Autowired
public AMQPEventSubscriber(final AmqpAdmin amqpAdmin,
final ConnectionFactory connectionFactory,
final ObjectMapper objectMapper) {
mConnectionFactory = connectionFactory;
mAmqpAdmin = amqpAdmin;
mObjectMapper = objectMapper;
}
#Override
public <T extends DomainEvent<?>> void subscribe(final Class<T> topic, final EventHandler<T> handler) {
final EventName topicName = topic.getAnnotation(EventName.class);
if (topicName != null) {
final MessageListenerAdapter adapter = new MessageListenerAdapter(handler, "handleEvent");
final Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();
converter.setJsonObjectMapper(mObjectMapper);
adapter.setMessageConverter(converter);
final Queue queue = new Queue(handler.getId(), true, false, false, QUEUE_ARGS);
mAmqpAdmin.declareQueue(queue);
final Binding binding = BindingBuilder.bind(queue).to(Constants.DOMAIN_EVENT_TOPIC).with(topicName.value());
mAmqpAdmin.declareBinding(binding);
final SimpleMessageListenerContainer listener = new SimpleMessageListenerContainer(mConnectionFactory);
listener.setQueues(queue);
listener.setMessageListener(adapter);
listener.start();
} else {
throw new IllegalArgumentException("subscribed Event type has no exchange key!");
}
}
}
Part of my handler app:
#Component
public class FooEventHandler implements EventHandler<FooEvent> {
private final UserCallbackMessenger mUserCallbackMessenger;
private final HorseTeamPager mHorseTeamPager;
#Autowired
public FooEventHandler(final EventSubscriber subscriber) {
subscriber.subscribe(FooEvent.class, this);
}
#Override
public void handleEvent(final FooEvent event) {
// do stuff
}
}
I wonder why out-of-the-box feature with the RabbitAdmin and beans for Broker entities doesn't fit your requirements:
A further benefit of doing the auto declarations in a listener is that if the connection is dropped for any reason (e.g. broker death, network glitch, etc.) they will be applied again the next time they are needed.
See more info in the Reference Manual.
This code base on the link below:
http://docs.xamarin.com/guides/android/platform_features/maps_and_location/part_3_-_location_services
I could not get any Lat/Lon ( Gps/Wifi)
The code is below :
I have added:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<:uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Android.Locations
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
//-- add these
using Android.Locations;
using System.Collections.Generic;
using System.Threading;
using System.Text;
using System.Linq;
using System.Xml;
namespace GPSWifi
{
[Activity (Label = "GPSWifi", MainLauncher = true)]
public class Activity1 : Activity
{
int count = 1;
private LocationManager _locMgr;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
InitializeLocationManager();
}
private void InitializeLocationManager()
{
_locMgr = (LocationManager) GetSystemService(LocationService);
var locationCriteria = new Criteria();
locationCriteria.Accuracy = Accuracy.NoRequirement;
locationCriteria.PowerRequirement = Power.NoRequirement;
string locationProvider = _locMgr.GetBestProvider(locationCriteria, true);
_locMgr.RequestLocationUpdates (locationProvider, 2000, 1, this);
}
protected override void OnResume ()
{
base.OnResume ();
_locMgr.RequestLocationUpdates (LocationManager.GpsProvider, 2000, 1, this);
}
protected override void OnPause ()
{
base.OnPause ();
_locMgr.RemoveUpdates (this);
}
public void OnProviderDisabled(string provider) {}
public void OnProviderEnabled(string provider) {}
public void OnLocationChanged (Location location)
{
var locationText = FindViewById<TextView>(Resource.Id.locationTextView);
locationText.Text = String.Format ("Latitude = {0}, Longitude = {1}",
location.Latitude, location.Longitude);
}
}
}
Your help is much appreciated.
-- Error Message :
C:\Program Files
(x86)\MSBuild\Xamarin\Android\Xamarin.Android.Common.targets(2,2):
Error MSB4018: The "Aapt" task failed unexpectedly.
System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Xamarin.Android.Tasks.BuildToolsUtils.GetBuildToolsPath(String
androidSdkDirectory)
at Xamarin.Android.Tasks.Aapt.GenerateFullPathToTool()
at Microsoft.Build.Utilities.ToolTask.ComputePathToTool()
at Microsoft.Build.Utilities.ToolTask.Execute()
at Xamarin.Android.Tasks.Aapt.Execute()
at
Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
at
Microsoft.Build.BackEnd.TaskBuilder.d__20.MoveNext()
(MSB4018) (GPSWifi)
This error: The "Aapt" task failed unexpectedly. has just started occurring recently - I think it's to do with the very latest sdk's from Android/Google - I think they've moved a file location.
Check other questions like Xamarin Studio 2 - latest stable update - Error executing task Aapt: The source sequence is empty
Then check with Xamarin support - they'll issue an update to fix this.
Any links to a good template for a windows service? (looking for C# code)
Something that has the basic functionality that I could extend.
It is a little clear what you are looking for. The Windows Service project type in Visual Studio creates a project with the templates you need to get going with a basic windows service.
You can also look at this article from C# Online. It goes over a few ideas and has a few parts to the article. (Note; the page seems to loads a little slow so be patient)
I use VS2005 and I like to start with the basic template.
Modify the Service class to this
using System;
using System.ServiceProcess;
using System.Timers;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
//better is to read from settings or config file
private readonly Double _interval = (new TimeSpan(1, 0, 0, 0)).TotalMilliseconds;
private Timer m_Timer;
public Service1()
{
InitializeComponent();
Init();
}
private void Init()
{
m_Timer = new Timer();
m_Timer.BeginInit();
m_Timer.AutoReset = false;
m_Timer.Enabled = true;
m_Timer.Interval = 1000.0;
m_Timer.Elapsed += m_Timer_Elapsed;
m_Timer.EndInit();
}
private void m_Timer_Elapsed(object sender, ElapsedEventArgs e)
{
//TODO WORK WORK WORK
RestartTimer();
}
private void RestartTimer()
{
m_Timer.Interval = _interval;
m_Timer.Start();
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
Start();
}
protected override void OnStop()
{
Stop();
base.OnStop();
}
public void Start()
{
m_Timer.Start();
}
public new void Stop()
{
m_Timer.Stop();
}
}
}
Install using InstallUtil.exe, after you have added an installer : http://msdn.microsoft.com/en-us/library/ddhy0byf(VS.80).aspx
Keep the Init function small and fast, otherwise your service will not start with an error that the service did not respond in a timely fashion
Hope this helps