I'm trying to bind the DataSource of a MapTileSource to a property on my view model, but I am getting the error REGDB_E_CLASSNOTREG on the Maps:MapTileSource line (underlined in blue is VS editor). I could always use a binding helper to achieve the same effect (I needed to in the 8.0 version of my app) but this seems like it should just...work. Any idea what is wrong?
<Maps:MapControl Style="{Binding Path=MapStyle}" Center="{Binding Path=MapCenter, Mode=TwoWay}" ZoomLevel="{Binding Path=ZoomLevel, Mode=TwoWay}" MapServiceToken="">
<Maps:MapControl.TileSources>
<Maps:MapTileSource Layer="BackgroundReplacement" DataSource="{Binding Path=BaseLayerDataSource}" />
</Maps:MapControl.TileSources>
</Maps:MapControl>
I also tried with just a static data source with the same effect:
<Maps:MapControl Style="{Binding Path=MapStyle}" Center="{Binding Path=MapCenter, Mode=TwoWay}" ZoomLevel="{Binding Path=ZoomLevel, Mode=TwoWay}" MapServiceToken="">
<Maps:MapControl.TileSources>
<Maps:MapTileSource Layer="BackgroundReplacement">
<Maps:MapTileSource.DataSource>
<Maps:HttpMapTileDataSource UriFormatString="" />
</Maps:MapTileSource.DataSource>
</Maps:MapTileSource>
</Maps:MapControl.TileSources>
</Maps:MapControl>
Edit: I tried the sample code at http://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn632728.aspx and it works fine, so it seems obvious that the MapTileSource itself is not unregistered. But that is all codebehind and uses no data binding, so it is not of much use to me.
Edit 2: If I ignore the error and try to deploy the app to the phone emulator, I get this on InitializeComponent() of the view:
An exception of type 'Windows.UI.Xaml.Markup.XamlParseException' occurred in HikePoint.exe but was not handled in user code
WinRT information: Cannot deserialize XBF metadata type list as '%1' was not found in namespace '%0'. [Line: 0 Position: 0]
Additional information: The text associated with this error code could not be found.
Cannot deserialize XBF metadata type list as '%1' was not found in namespace '%0'. [Line: 0 Position: 0]
If there is a handler for this exception, the program may be safely continued.
What's your project platform target ? Try to change it to x64.
Similar Question on SO
I eventually gave up and just made a behavior to handle the binding for me.
public class TileSourceBehavior : DependencyObject, IBehavior
{
public DependencyObject AssociatedObject { get; private set; }
public void Attach(Windows.UI.Xaml.DependencyObject associatedObject)
{
var mapControl = associatedObject as MapControl;
if (mapControl == null)
throw new ArgumentException("TileSourceBehavior can be attached only to MapControl");
AssociatedObject = associatedObject;
}
public void Detach() { }
public static readonly DependencyProperty TileSourceProperty =
DependencyProperty.Register("TileSource", typeof(MapTileSource), typeof(TileSourceBehavior), new PropertyMetadata(null, OnTileSourcePropertyChanged));
public MapTileSource TileSource
{
get { return GetValue(TileSourceProperty) as MapTileSource; }
set { SetValue(TileSourceProperty, value); }
}
private static void OnTileSourcePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var behavior = dependencyObject as TileSourceBehavior;
var mapControl = behavior.AssociatedObject as MapControl;
// remove the existing tile source
var existingTileSource = mapControl.TileSources.FirstOrDefault(t => t.Layer == MapTileLayer.BackgroundReplacement);
if (existingTileSource != null)
mapControl.TileSources.Remove(existingTileSource);
// add the tile source
behavior.TileSource.Layer = MapTileLayer.BackgroundReplacement;
mapControl.TileSources.Add(behavior.TileSource);
}
}
You use it thus, where TileSource is a MapTileSource property on your ViewModel.
<Maps:MapControl>
<i:Interaction.Behaviors>
<behaviors:TileSourceBehavior TileSource="{Binding Path=TileSource}" />
</i:Interaction.Behaviors>
</Maps:MapControl>
Related
//Original method:
#Autowired
private ConversionServiceValidator validator;
public CRSConversionResult convertCRS(ConvertCrsVo convertCrsVo) throws Exception {
if (validator.isSameSourceAndTarget(convertCrsVo))
throw new ValidationException(Constants.BADREQUEST);
if (convertCrsVo.getPreferredTransforms() != null) {
List<TransformVo> preferredTransformList = new ArrayList<>();
for (TransformVo transformVo : convertCrsVo.getPreferredTransforms()) {
preferredTransformList.add(getPerfByCode(transformVo));
}
convertCrsVo.setPreferredTransforms(preferredTransformList);
}
convertCrsVo.setSourceCRS(getCrsVoByCode(convertCrsVo.getSourceCRS()));
convertCrsVo.setTargetCRS(getCrsVoByCode(convertCrsVo.getTargetCRS()));
convertCrsVo = validator.replaceCoordinates(convertCrsVo);
logger.info("ShellGeodeticService::convertCRS::Request to GeoCalService convertpoints::" + mapper.writeValueAsString(convertCrsVo));
ConvertPointsResponse response = geoCalService.convertCRS(convertCrsVo);
CRSConversionResult result = new CRSConversionResult();
result.setCriteriaMessage(response.getCriteriaMessage());
result.setResultPoints(response.getResultPoints());
result.setTransformName(response.getTransformName());
result.setTransformDescription(response.getTransformDescription());
// added schema as per pbi 195298
List<ConvertedTransformsResult> transformsResults = new ArrayList<>();
if (response.getTransforms() != null || !response.getTransforms().isEmpty())
response.getTransforms().stream().forEach(
t -> transformsResults.add(new ConvertedTransformsResult().getConvertedTransformsResult(t)));
result.setTransforms(transformsResults);
String logmessage=generateLogMessage(result,convertCrsVo);
logger.info(logmessage);
validator.isResponseValid(result);
return result;
}
//The testcase for the above method
#Test
public void testconvertCRSJob() throws Exception{
ConvertCrsVo convertCrsVo = TestDataFactory.getConvertCrsVo();
CRSConversionResult crsConversionResult = TestDataFactory.getCRSConversionResult();
ConversionServiceValidator conversionServiceValidatorMock = mock(ConversionServiceValidator.class);
Mockito.when(geoCalService.convertCRS(Mockito.any()))
.thenReturn(TestDataFactory.getConvertPointsResponse(convertCrsVo));
Mockito.when(validator.replaceCoordinates(convertCrsVo))
.thenReturn(TestDataFactory.getConvertCrsVo());
Mockito.when(geoCalService.search(Mockito.any(SearchFilter.class)))
.thenReturn(TestDataFactory.getSearchResultResponseForCRS());
Mockito.when(shellGeodeticService.convertCRS(convertCrsVo))
.thenReturn(TestDataFactory.getCRSConversionResult());
shellGeodeticService.convertCRSJob();
}
The error that i am getting is as below:
org.mockito.exceptions.misusing.CannotStubVoidMethodWithReturnValue:
'isResponseValid' is a void method and it cannot be stubbed with a return value!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. The method you are trying to stub is overloaded. Make sure you are calling the right overloaded version.
2. Somewhere in your test you are stubbing final methods. Sorry, Mockito does not verify/stub final methods.
3. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
4. Mocking methods declared on non-public parent classes is not supported.
at com.shell.geodetic.GeodeticConvertionApiAppTests.testconvertCRSJob(GeodeticConvertionApiAppTests.java:1783)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
Can someone help me on how to stub the void method "isResponseValid" ? I tried around 100 combinations that i saw in SOF and nothing worked. Thanks for the help in advance.
*Edit
Class ConversionServiceValidator {
public void isResponseValid(CRSConversionResult response) throws InvalidDataException {
if (response.getResultPoints().isEmpty() || response.getResultPoints() == null) {
throw new ValidationException("Request body has incorrect format");
} else {
for (Point point : response.getResultPoints()) {
if (point.getX().trim().equals("0") || point.getY().trim().equals("0")) {
throw new InvalidDataException(400, "Bad Request", "WARNING: Not all points could be converted",
response);
}
}
}
It is a mock #InjectMocks ShellGeodeticService shellGeodeticService;
shellGeodeticService is not a mock. #InjectMocks is used for the class under test, where the mocks are injected into.
That implies you can not use
Mockito.when(shellGeodeticService.convertCRS(convertCrsVo))
.thenReturn(TestDataFactory.getCRSConversionResult());
in your test as only mocks(or spys) can be used within Mockito.when.
Actually im trying to run test case for shellGeodeticService.convertCRS() and since it calls isResponseValid method internally , i have to mock that also right?
No, that is incorrect. If validator is a mock every method invocation will do nothing by default. So, unless you want to throw an exception, you do not need to define anything.
As your question lacks some details, I assume a complete version of your test could be similiar to this:
#InjectMocks
ShellGeodeticService shellGeodeticService;
#Mock
ConversionServiceValidator validator;
#Mock
... geoCalService; // some unknown class
#Test
public void testconvertCRSJob() throws Exception{
ConvertCrsVo convertCrsVo = TestDataFactory.getConvertCrsVo();
// Note sure whether this is correct by your logic as there is no `replacement` happening.
Mockito.when(validator.replaceCoordinates(convertCrsVo)).thenReturn(convertCrsVo);
Mockito.when(geoCalService.convertCRS(Mockito.any())).thenReturn(TestDataFactory.getConvertPointsResponse(convertCrsVo));
CRSConversionResult result = shellGeodeticService.convertCRS();
// do some assertions on the result
}
As validator is a mock:
validator.isSameSourceAndTarget(convertCrsVo) returns false be default
validator.isResponseValid( ... ) does nothing by default
As you did not add the methods getCrsVoByCode, getPerfByCode and generateLogMessage take note that if there are any further interactions with the mocked objects you'll need to add them.
(eg.: a call to geoCalService.search is not visible in your test code, so I removed the behaviour definition from the test displayed above)
We have upgrade our application to use CDI beans. This change was very smooth when we are deploying our application on Wildfly 10.x, but when we tried to deploy the same application on Websphere Classic and Liberty some problems came up.
We have look for several questions already posted here, like this, this, this or this, but none of the answers were able to solve our problem.
On my localhost I am using Websphere Liberty Profile with webProfile-7.0, meaning CDI-1.2, EL-3.0, JSF-2.2 and servlet-3.1.
Our application also uses Primefaces 6.0.
The problem occurs on a phaseListener. On it, we are injecting a Bean annotated with both #Named (javax.inject.Named) and #SessionScoped (javax.enterprise.context.SessionScoped).
When the injected variable is called on the phaseListener the following error is thrown.
[err] 2017-05-10 09:45:06 ERROR MWExceptionHandler:139 - A server exception occurred
org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:691)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:89)
at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:164)
at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125)
at web.frmwrk.mgbean.WebSession$Proxy$_$$_WeldClientProxy.getLocale(Unknown Source)
at web.frmwrk.application.LocaleFaceletViewHandler.calculateLocale(LocaleFaceletViewHandler.java:43)
at javax.faces.application.ViewHandlerWrapper.calculateLocale(ViewHandlerWrapper.java:76)
at org.apache.myfaces.application.ResourceHandlerImpl.getLocalePrefixForLocateResource(ResourceHandlerImpl.java:715)
at org.apache.myfaces.application.ResourceHandlerImpl.createViewResource(ResourceHandlerImpl.java:1609)
at org.apache.myfaces.application.ResourceHandlerImpl.createViewResource(ResourceHandlerImpl.java:62)
at javax.faces.application.ResourceHandlerWrapper.createViewResource(ResourceHandlerWrapper.java:83)
at javax.faces.application.ResourceHandlerWrapper.createViewResource(ResourceHandlerWrapper.java:83)
at javax.faces.application.ResourceHandlerWrapper.createViewResource(ResourceHandlerWrapper.java:83)
at javax.faces.application.ResourceHandlerWrapper.createViewResource(ResourceHandlerWrapper.java:83)
at org.apache.myfaces.view.facelets.impl.DefaultResourceResolver.resolveUrl(DefaultResourceResolver.java:53)
at org.apache.myfaces.view.facelets.impl.DefaultResourceResolver.resolveUrl(DefaultResourceResolver.java:39)
at org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage.viewExists(FaceletViewDeclarationLanguage.java:325)
at org.apache.myfaces.shared.application.DefaultViewHandlerSupport.checkResourceExists(DefaultViewHandlerSupport.java:573)
at org.apache.myfaces.shared.application.DefaultViewHandlerSupport.handleSuffixMapping(DefaultViewHandlerSupport.java:507)
at org.apache.myfaces.shared.application.DefaultViewHandlerSupport.calculateViewId(DefaultViewHandlerSupport.java:113)
at org.apache.myfaces.application.ViewHandlerImpl.deriveLogicalViewId(ViewHandlerImpl.java:122)
at javax.faces.application.ViewHandlerWrapper.deriveLogicalViewId(ViewHandlerWrapper.java:112)
at javax.faces.application.ViewHandlerWrapper.deriveLogicalViewId(ViewHandlerWrapper.java:112)
at javax.faces.application.ViewHandlerWrapper.deriveLogicalViewId(ViewHandlerWrapper.java:112)
at javax.faces.application.ViewHandlerWrapper.deriveLogicalViewId(ViewHandlerWrapper.java:112)
at org.apache.myfaces.lifecycle.RestoreViewExecutor.execute(RestoreViewExecutor.java:225)
at org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:196)
at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:143)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:198)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1290)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:778)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:475)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.invokeTarget(WebAppFilterChain.java:148)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:79)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:1021)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1143)
at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.dispatch(WebAppRequestDispatcher.java:1381)
at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.include(WebAppRequestDispatcher.java:541)
at com.ibm.ws.webcontainer.webapp.WebApp.sendError(WebApp.java:4265)
at com.ibm.ws.webcontainer.webapp.WebApp.handleException(WebApp.java:5031)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:5011)
at com.ibm.ws.webcontainer31.osgi.webapp.WebApp31.handleRequest(WebApp31.java:525)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.handleRequest(DynamicVirtualHost.java:315)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:1014)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.run(DynamicVirtualHost.java:280)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:967)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.wrapHandlerAndExecute(HttpDispatcherLink.java:359)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.ready(HttpDispatcherLink.java:318)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:471)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleNewRequest(HttpInboundLink.java:405)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.processRequest(HttpInboundLink.java:285)
at com.ibm.ws.http.channel.internal.inbound.HttpICLReadCallback.complete(HttpICLReadCallback.java:66)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.requestComplete(WorkQueueManager.java:504)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.attemptIO(WorkQueueManager.java:574)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.workerRun(WorkQueueManager.java:929)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager$Worker.run(WorkQueueManager.java:1018)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
[ERROR ] SRVE0777E: Exception thrown by application class 'javax.faces.webapp.FacesServlet.service:230'
javax.servlet.ServletException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:230)
at [internal classes]
Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:691)
at [internal classes]
at web.frmwrk.mgbean.WebSession$Proxy$_$$_WeldClientProxy.getLocale(Unknown Source)
at web.frmwrk.application.LocaleFaceletViewHandler.calculateLocale(LocaleFaceletViewHandler.java:43)
at javax.faces.application.ViewHandlerWrapper.calculateLocale(ViewHandlerWrapper.java:76)
... 1 more
Here is Session Scoped bean we wish to inject
#Named("ws")
#SessionScoped
public class WebSession extends LoggableBean {
private static final long serialVersionUID = 5L;
#Inject
protected WebApplication wa;
/** True if session originates from a trusted logon */
private boolean trusted = false;
/**
* Current user, null if not logged in (this may be a simulated user token if {#link #simulateUser(int)} was called
* before.
*/
private ISofTokenType userToken;
/**
* Original login user (identical to userToken if not simulating another user
*/
private ISofTokenType loginUserToken;
/** Current locale of the websession. */
private Locale locale;
/** The policy rules resolver for this session */
private transient PolicyResolver policy;
#Inject
protected Config config;
#Inject
protected WebPaths path;
#Inject
protected WebApplicationStore waStore;
#PostConstruct
protected void init() {
try {
setLocale(LocaleUtils.getDefaultLanguage().getCode());
} catch (ConfigurationException ex) {
// Fallback to default language in config.xml
getLog().error(ex);
locale = FacesContext.getCurrentInstance().getApplication().getDefaultLocale();
}
}
/**
* Check if the currentRelease session is linked with a logged in user or if the visitor is a guest.
*
* #return True if the user is logged in, false otherwise.
*/
public boolean isLoggedIn() {
return userToken != null;
}
}
And here the phaseListener
public class PolicyController implements PhaseListener {
private static final long serialVersionUID = 2189917635371117541L;
private static final Log log = LogFactory.getLog(PolicyController.class);
private static final String VALIDATION_ERROR_DEFAULT_KEY = "validation_error_default";
private static final String COMPONENT_ATTRIBUTE_RENDERED_MODIFIED_BY_RULE = "rendered-modified-by-policy";
private static enum PhaseMoment {
BEFORE, AFTER
};
#Inject
private WebSession ws;
public void beforePhase(PhaseEvent event) {
if (!FacesHelper.getConfig().getBoolean(Properties.POLICY_CONTROLLER_ENABLED, true)) {
if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) log.debug("Policy is disabled");
return;
}
if ((event.getPhaseId() == PhaseId.RENDER_RESPONSE || event.getPhaseId() == PhaseId.PROCESS_VALIDATIONS)
&& ws.isLoggedIn()) { // <- Error happens here
// Apply the rules...
FacesContext fc = event.getFacesContext();
log.debug("Run PolicyController before " + event.getPhaseId() + " (viewroot has "
+ fc.getViewRoot().getChildCount() + " direct children)");
traverseComponent(fc, fc.getViewRoot(), event.getPhaseId(), PhaseMoment.BEFORE);
}
}
public void afterPhase(PhaseEvent event) {
if (!FacesHelper.getConfig().getBoolean(Properties.POLICY_CONTROLLER_ENABLED, true)) {
return;
}
if ((event.getPhaseId() == PhaseId.PROCESS_VALIDATIONS || event.getPhaseId() == PhaseId.RESTORE_VIEW)
&& ws.isLoggedIn()) { // <- Error happens here
FacesContext fc = event.getFacesContext();
log.debug("Run PolicyController after " + event.getPhaseId() + " (viewroot has "
+ fc.getViewRoot().getChildCount() + " direct children)");
traverseComponent(fc, fc.getViewRoot(), event.getPhaseId(), PhaseMoment.AFTER);
}
}
}
I've also tried adding
FacesContext context = event.getFacesContext();
WebSession webSession = context.getApplication().evaluateExpressionGet(context, "#{ws}", WebSession.class);
before the if statement and use webSession instead of ws, but got the same error.
Once again, I would like to point that this is working fine in Wildfly, which lead us to assume we are implementing the code correctly. Also, we are sure we are using Java 8 and the server supports JEE7, so, from all the places we've looked we were assuming this should be something to be supported on our version of Websphere.
We have the exact same problem when deploying the app on Websphere Classic 9.0.
The only difference we find so far is that Websphere uses Myfaces while Wildfly uses Mojarra. Can this be some kind of bug in Myfaces? Is there any specific configuration or code we need to use to support this kind of things?
If you need more info about our implementation that may help to figure out the cause of this, just let me know what.
Following up on this issue 4 years too late, but, in case others find it, the solution should be to set deferServletRequestListenerDestroyOnError as true on WebSphere.
Or just add this to the server.xml if you're on Liberty:
<webContainer deferServletRequestListenerDestroyOnError="true" />
https://www.ibm.com/support/pages/apar/PI26908
A explanation of this property can be found here: https://github.com/OpenLiberty/open-liberty/issues/18281#issuecomment-1353399402
I'm experimenting with interception in Castle Windsor and notice that interceptors seem to be created as decorators of my service interface.
In other words, if I have an interface "ISomethingDoer" and a concrete "ConcreteSomethingDoer", the proxy implements ISomethingDoer but does not inherit from ConcreteSomethingDoer.
This is fine, and no doubt by design, but what I'm wondering is whether I can intercept protected virtual methods in my concrete classes that wouldn't be known by the public interface. I am doing this in order to add logging support, but I might want to log some of the specific internal details of a class.
In my slightly unimaginative test case I have this:
public interface ISomethingDoer
{
void DoSomething(int Count);
}
[Loggable]
public class ConcreteSomethingDoer : ISomethingDoer
{
public void DoSomething(int Count)
{
for (var A = 0; A < Count; A++)
{
DoThisThing(A);
}
}
[Loggable]
protected virtual void DoThisThing(int A)
{
("Doing a thing with " + A.ToString()).Dump();
}
}
So what I want to do is log calls to "DoThisThing" even though it's not part of the interface.
I've managed to get this working in Autofac. (I've created a Linqpad script here: http://share.linqpad.net/frn5a2.linq) but am struggling with Castle Windsor (see http://share.linqpad.net/wn7877.linq)
In both cases my interceptor is the same and looks like this:
public class Logger : IInterceptor
{
public void Intercept(IInvocation Invocation)
{
String.Format("Calling method {0} on type {1} with parameters {2}",
Invocation.Method.Name,
Invocation.InvocationTarget.GetType().Name,
String.Join(", ", Invocation.Arguments.Select(a => (a ?? "*null*").ToString()).ToArray())).Dump();
Invocation.Proceed();
"Done".Dump();
}
}
What I really want to do is say "any classes with a [Loggable] attribute, should use the logging interceptor". In the Autofac example I've specifically attached a logger to the registration, whereas with Castle I'm using an IModelInterceptorsSelector which looks like this:
public class LoggerInterceptorSelector : IModelInterceptorsSelector
{
public bool HasInterceptors(ComponentModel Model)
{
return Model.Implementation.IsDefined(typeof(LoggableAttribute), true);
}
public InterceptorReference[] SelectInterceptors(ComponentModel Model, InterceptorReference[] Interceptors)
{
return new[]
{
InterceptorReference.ForType<Logger>()
};
}
}
Finally, the code to execute all this is:
var Container = new WindsorContainer();
Container.Register(
Component.For<Logger>().LifeStyle.Transient
);
Container.Kernel.ProxyFactory.AddInterceptorSelector(new LoggerInterceptorSelector());
Container.Register(
Component.For<ISomethingDoer>()
.ImplementedBy<ConcreteSomethingDoer>()
.LifeStyle.Transient
);
var Doer = Container.Resolve<ISomethingDoer>();
Doer.DoSomething(5);
When run I would expect to see "Calling method DoThisThing with parameters x" for each time the method is called. Instead I only get the call to DoSomething logged.
I can see why Castle Windsor is doing this, but I'm wondering if there is a way to tweak the behaviour?
(As a side-note I don't want to use Windsor's own interceptor attributes as I don't want to introduce dependencies to Castle outside of my composition root.)
I have tried resolving the ConcreteSomethingDoer specifically and this works, but not if I'm resolving the ISomethingDoer.
Apologies for the long post, and also apologies because I am pretty new to Castle Windsor!
I you could register like:
Container.Register(
Component.For<ISomethingDoer, ConcreteSomethingDoer>()
.ImplementedBy<ConcreteSomethingDoer>()
.LifeStyle.Transient
);
This should create a class proxy by deriving from ConcreteSomethingDoer. However this won't work with dynamic interceptors. However you probably can work around that by creating a facility which registers the interceptor when needed.
I would like create own aspects with Castle Windsor Interceptor and apply on View Model classes.
As I said I use Caliburn MVVM framework and on DI I use Caste Windsor. Everything works good.
For example I created simple loggging interceptors, here is:
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.Write("Log: Method Called: " + invocation.Method.Name);
invocation.Proceed();
}
}
This is simple View Model class - it is "tab item" :
public class TabViewModel : Screen,
ITabViewModel
{
}
When I configure IoC with Fluent API I would like apply this interceptor on View Model class.
container.Register(Component
.For<LoggingInterceptor>()
.LifeStyle
.Singleton
.Named("LogAspect"));
container.Register(Component
.For<ITabViewModel>()
.ImplementedBy<TabViewModel>()
.LifeStyle
.Transient
.Named("TabViewModel")
.Interceptors<LoggingInterceptor>());
When I tried pick view model from IoC:
var tabItem = IoC.Get<ITabViewModel>();
ActivateItem(tabItem);
I got this message:
A default view was not found for Castle.Proxies.ITabViewModelProxy.
Views searched for include: Castle.Proxies.IITabViewModelProxy
Castle.Proxies.ITabViewModelProxys.IDefault
Castle.Proxies.ITabViewModelProxys.Default
Also I tried this way for interceptor applicaion.
[Interceptor(typeof(LoggingInterceptor))]
public class TabViewModel : Screen,
ITabViewModel
{
}
Ok, I know that Caliburn framework match View and View Model by naming convention.
When I try pick implementation of ITabViewModel I get ITabViewModelProxy and for ITabViewModelProxy I didn’t register any View.
Target of proxy is TabViewModel but I think problem is with naming mismatch.
I dont want rename ViewModel because I would like configure proxies from XML files.
So what is correct way?
Thank you for help
What about this?
void Hack()
{
var existing = ViewLocator.TransformName;
ViewLocator.TransformName = (s, o) =>
existing(s.EndsWith("Proxy")
? s.Substring(0, s.Length - "Proxy".Length)
: s, o);
}
The easiest way (and probably robust) is to suggest to Caliburn's ViewLocator to use not the type of view model's proxy but the type of the view model that's being proxied:
public static void AddViewLocatorRuleForProxiedViewModels()
{
var originalViewTypeLocator = ViewLocator.LocateTypeForModelType;
ViewLocator.LocateTypeForModelType = (modelType, displayLocation, context) =>
{
var viewModelType = modelType;
var viewModelTypeName = viewModelType.FullName;
if (viewModelTypeName.StartsWith("Castle.Proxies") && viewModelTypeName.EndsWith("Proxy"))
viewModelType = viewModelType.BaseType;
return originalViewTypeLocator(viewModelType, displayLocation, context);
};
}
I am getting time out from using JsonpRequestBuilder.
The entry point code goes like this:
// private static final String SERVER_URL = "http://localhost:8094/data/view/";
private static final String SERVER_URL = "http://www.google.com/calendar/feeds/developer-calendar#google.com/public/full?alt=json-in-script&callback=insertAgenda&orderby=starttime&max-results=15&singleevents=true&sortorder=ascending&futureevents=true";
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";
/**
* This is the entry point method.
*/
public void onModuleLoad() {
JsonpRequestBuilder requestBuilder = new JsonpRequestBuilder();
// requestBuilder.setTimeout(10000);
requestBuilder.requestObject(SERVER_URL, new Jazz10RequestCallback());
}
class Jazz10RequestCallback implements AsyncCallback<Article> {
#Override
public void onFailure(Throwable caught) {
Window.alert("Failed to send the message: " + caught.getMessage());
}
#Override
public void onSuccess(Article result) {
// TODO Auto-generated method stub
Window.alert(result.toString());
}
The article class is simply:
import com.google.gwt.core.client.JavaScriptObject;
public class Article extends JavaScriptObject {
protected Article() {};
}
The gwt page, however, always hit the onFailure() callback and show this alert:
Failed to send the message. Timeout while calling <url>.
Fail to see anything on the Eclipse plugin console. I tried the url and it works perfectly.
Would appreciate any tip on debugging technique or suggestion
Maybe you should set the callback function explicitly via setCallbackParam, since you have callback=insertAgenda in your url - I presume that informs the server what should be the name of the callback function that wraps the JSON.
Also, it's worth checking Firebug's console (or a similar tool for your browser) - even if GWT doesn't report any exceptions, Firebug still might.
PS: It's useful to use a tool like Firebug to see if the application does in fact receive the response from the server (that would mean that, for example, you do need the setCallbackParam call) or maybe there's something wrong on the server side (for whatever reason).
You have to read the callback request-Parameter (default callback, value something like __gwt_jsonp__.P0.onSuccess) on serversite and have to modify the output to
<callback>(<json>);
In this case:
__gwt_jsonp__.P0.onSuccess(<json>);
Both of these guys are absolutely correct, but here is a concrete example to help you understand exactly what they are referring too.
This is a public JSON api. Take a look at the results:
http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4
This public API supports JSONP through the predefined parameter 'callback'. Basically whatever value you pass into callback, will be used as the function name to wrap around the JSON data you desire. Take a look at the results of these few requests:
http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4&callback=totallyMadeUp
http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4&callback=trollingWithJSONP
It could be happening because of another reason, that the webservice call is returning a JSON object and but the callback is expecting JSONP object (note there is a difference).
So if you are dealing with google maps api, and you are seeing this exception, you need to change it to api provide by maps api, something like
final GeocoderRequest request = GeocoderRequest.create();
request.setAddress(query);
try {
GWT.log("sending GeoCoderRequest");
if (m_geocoder == null) {
m_geocoder = Geocoder.create();
}
m_geocoder.geocode(request, new Geocoder.Callback() {
#Override
public void handle(final JsArray<GeocoderResult> results,
final GeocoderStatus status) {
handleSuccess(results, status);
}
});
} catch (final Exception ex) {
GWT.log("GeoCoder", ex);
}
Or else you could use RequestBuilder as in gwt library.