UWP RfComm - StreamSocketListener.BindServiceNameAsync throws exception - bluetooth

I am trying to create a UWP app that listens for Bluetooth serial port connections. When I set up the listener in the application (via a button click) I get an exception at the line:
await socketListener.BindServiceNameAsync(
rfcommProvider.ServiceId.ToString(),
SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);`
The exception message is:
System.ArgumentException: 'The parameter is incorrect.
'protectionLevel': Only plain sockets are allowed for IP StreamSocketListeners.'
Here is the code:
private async void btnBluetoothServerClick(object sender, RoutedEventArgs e)
{
var rfcommProvider =
await RfcommServiceProvider.CreateAsync(RfcommServiceId.SerialPort);
var socketListener = new StreamSocketListener();
socketListener.ConnectionReceived += OnConnectionReceived;
await socketListener.BindServiceNameAsync(
rfcommProvider.ServiceId.ToString(),
SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
rfcommProvider.StartAdvertising(socketListener);
}
When the protectionLevel parameter SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication, is changed to, SocketProtectionLevel.PlainSocketas the exception indicates, the new exception message is: System.Exception: 'The specified class was not found. (Exception from HRESULT: 0x8007277D)'.
The application manifest file includes:
<Capabilities>
<Capability Name="internetClient" />
<DeviceCapability Name="bluetooth" />
<DeviceCapability Name="proximity" />
<DeviceCapability Name="serialcommunication">
<Device Id="any">
<Function Type="name:serialPort" />
</Device>
</DeviceCapability>
<DeviceCapability Name="bluetooth.rfcomm">
<Device Id="any">
<Function Type="name:serialPort" />
</Device>
</DeviceCapability>
<DeviceCapability Name="wifiControl" />
</Capabilities>
It seems that this code should work according to the documentation at:
https://learn.microsoft.com/en-us/uwp/api/windows.networking.sockets.streamsocketlistener#Windows_Networking_Sockets_StreamSocketListener_BindServiceNameAsync_System_String_Windows_Networking_Sockets_SocketProtectionLevel_Windows_Networking_Connectivity_NetworkAdapter_
What am I doing wrong?

Just change parameter of the BindServiceNameAsync method,
rfcommProvider.ServiceId.ToString()
to
rfcommProvider.ServiceId.AsString()
then your code snippet will work.
The AsString() method of RfcommServiceId will convert the RfcommServiceId to a string.ToString will return the type which is not the correct parameter for BindServiceNameAsync.
More details please reference the official sample.

Related

How can I take over writing an exception in log4net

We have a large Java application that we convert to .NET using IKVM. All of the log4j calls in it call a log4j wrapper we created that calls log4net. Mostly it works great.
But we have one problem - the logging does not give the stack trace or InnerException(s). I believe the problem is the .NET Exception.ToString() provides all that information while the Java Throwable.toString() is basically the Exception.Message.
So where log4net calls Exception.ToString(), I need to replace that for any exception that inherits from java.lang.Throwable to create the string. How can I do this?
Before calling Exception.ToString(), Log4net looks whether a custom IObjectRenderer has been registered for an Exception (as it also does for any other type).
In order to get a custom Exception output, you need to create and register a custom IObjectRenderer.
The one here below will output the Exception in uppercase.
You are free to build any error message string representation which you pass to writer.Write.
namespace PFX
{
public class MyExceptionRenderer : IObjectRenderer
{
public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
{
Exception exception = obj as Exception;
// Format the error message as pleased here.
String error = exception.ToString().ToUpper();
writer.Write(error);
}
}
}
You register the MyExceptionRenderer in your Log4net configuration as shown below.
<log4net>
<appender name="consoleAppender" type="log4net.Appender.ConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date | %logger | %level | %message | %exception%n" />
</layout>
</appender>
<root>
<level value="All" />
<appender-ref ref="consoleAppender" />
</root>
<renderer renderingClass="PFX.MyExceptionRenderer"
renderedClass="System.Exception" />
</log4net>
The code below
var logger = LogManager.GetLogger("AppLog");
var exception = new ApplicationException("Ooops");
logger.Error("An error occured.", exception);
will have the following log output.
Notice that the exception is in full caps.
2019-05-08 21:52:22,855 | AppLog | ERROR | An error occured. | SYSTEM.APPLICATIONEXCEPTION: OOOPS

Spring Integration - Scheduling Job from configuration file

I'm using Spring Integration to parse XML file and i will need to create a thread (and each one have a different rate) for each tag.
Right now (with the help of many users here :)) i'm able to split XML by tag and then route it to the appropiate service-activator.
This works great but i'm not able to redirect to a channel that create "a thread" and then execute the operations. Right now i have the following configuration and in my mind (that i dont know if it is correct...)
Split tag -> Route to the appropiate channel -> Start a thread(from tag configuration) -> Execute the operation
This is my actual configuration that split tag and redirect to the channel.
The router should redirect not toward a channel directly, but schedule them.
In first instance will be enought to redirect it in a pool with fixed rate and later i will use XPATH to get the attribute and then replace this "fixed" rate with the correct value.
I've tried many solutions to create this flow but each one fails or do not compile :(
<context:component-scan base-package="it.mypkg" />
<si:channel id="rootChannel" />
<si-xml:xpath-splitter id="mySplitter" input-channel="rootChannel" output-channel="routerChannel" create-documents="true">
<si-xml:xpath-expression expression="//service" />
</si-xml:xpath-splitter>
<si-xml:xpath-router id="router" input-channel="routerChannel" evaluate-as-string="true">
<si-xml:xpath-expression expression="concat(name(./node()), 'Channel')" />
</si-xml:xpath-router>
<si:service-activator input-channel="serviceChannel" output-channel="endChannel">
<bean class="it.mypkg.Service" />
</si:service-activator>
UPDATE:
Using this configuration for the service this should run a task every 10 seconds (the id=service1) and every 5 seconds the other (the id=service2). In the same way i can have another tag that is handle by another class (because this will have another behaviour)
<root>
<service id="service1" interval="10000" />
<service id="service2" interval="5000" />
<activity id="activity1" interval="50000" />
<root>
I will have a classe (Service) that is general to handle Service tag and this complete some operation and then "return me" the value so i can redirect to another channel.
public class Service {
public int execute() {
// Execute the task and return the value to continue the "chain"
}
}
It's not at all clear what you mean; you split a tag; route it but want to "schedule" it at a rate in the XML. It's not clear what you mean by "schedule" here - normally each message is processed once not multiple times on a schedule.
As I said, I don't understand what you need to do, but a smart poller might be suitable.
Another possibility is the delayer where the amount of the delay can be derived from the message.
EDIT
Since your "services" don't seem to take any input data, it looks like you simply need to configure/start an <inbound-channel-adapter/> for each service, and then start it, based on the arguments in the XML.
<int:inbound-channel-adapter id="service1" channel="foo"
auto-startup="false"
ref="service1Bean" method="execute">
<poller fixed-delay="1000" />
</int:inbound-channel-adapter/>
Note auto-startup="false".
Now, in the code that receives the split
#Autowired
SourcePollingChannelAdapter service1;
...
public void startService1(Node node) {
...
service1.setTrigger(new PeridicTrigger(...));
service1.start();
...
}
I dont know if this is the right way to implement the flow, but i've write the follow code:
applicationContext.xml
<context:component-scan base-package="it.mypkg" />
<!-- Expression to extract interval from XML tag -->
<si-xml:xpath-expression id="selectIntervalXpath" expression="//*/#interval" />
<si:channel id="rootChannel" />
<!-- Split each tag to redirect on router -->
<si-xml:xpath-splitter id="mySplitter" input-channel="rootChannel" output-channel="routerChannel" create-documents="true">
<si-xml:xpath-expression expression="//service|//activity" />
</si-xml:xpath-splitter>
<!-- Route each tag to the appropiate channel -->
<si-xml:xpath-router id="router" input-channel="routerChannel" evaluate-as-string="true">
<si-xml:xpath-expression expression="concat(name(./node()), 'Channel')" />
</si-xml:xpath-router>
<!-- Activator for Service Tag -->
<si:service-activator input-channel="serviceChannel" method="schedule">
<bean class="it.mypkg.Service" />
</si:service-activator>
<!-- Activator for Activity Tag -->
<si:service-activator input-channel="activityChannel" method="schedule">
<bean class="it.mypkg.Activity" />
</si:service-activator>
<!-- Task scheduler -->
<task:scheduler id="taskScheduler" pool-size="10"/>
Each tag will extend an Operation class (to avoid code duplication on bean injection)
Operation.java
public abstract class Operation {
protected TaskScheduler taskScheduler;
protected XPathExpression selectIntervalXpath;
abstract public void schedule(Node document);
#Autowired
public void setTaskScheduler(TaskScheduler taskScheduler) {
this.taskScheduler= taskScheduler;
}
public TaskScheduler getTaskScheduler() {
return this.taskScheduler;
}
#Autowired
public void setSelectIntervalXpath(XPathExpression selectIntervalXpath) {
this.selectIntervalXpath = selectIntervalXpath;
}
public XPathExpression getSelectIntervalXPath() {
return this.selectIntervalXpath;
}
}
And an example of Service class (that handle all tags service provided on .xml)
public class Service extends Operation {
private static final Logger log = Logger.getLogger(Service.class);
#Override
public void schedule(Node document) {
log.debug("Scheduling Service");
long interval = Long.parseLong(this.selectIntervalXpath.evaluateAsString(document));
this.taskScheduler.scheduleAtFixedRate(new ServiceRunner(), interval);
}
private class ServiceRunner implements Runnable {
public void run() {
log.debug("Running...");
}
}
}
Now to continue my flow i will need to find a way to redirect the output of each job to Spring Integration (applicationContext.xml).

ChannelResolutionException: no output-channel or replyChannel header available - Only with many requests

I am running the client portion of the Spring Integration TCP Multiplex example. I was trying to see how many requests it could handle at once and around 1000, I started to get this error: ChannelResolutionException: no output-channel or replyChannel header available
Everything is fine below about 1000 calls.
<beans:description>
Uses conversion service and collaborating channel adapters.
</beans:description>
<context:property-placeholder />
<converter>
<beans:bean class="org.springframework.integration.samples.tcpclientserver.ByteArrayToStringConverter" />
</converter>
<!-- Fastest Wire Protocol - takes a byte array with its length definied in the first x bytes-->
<beans:bean id="fastestWireFormatSerializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer">
<beans:constructor-arg value="1" />
</beans:bean>
<!-- Client side -->
<gateway id="gw"
service-interface="org.springframework.integration.samples.tcpclientserver.SimpleGateway"
default-request-channel="input" />
<ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="${availableServerSocket}"
single-use="false"
serializer="fastestWireFormatSerializer"
deserializer="fastestWireFormatSerializer"
so-timeout="10000" />
<publish-subscribe-channel id="input" />
<!-- scheduler - Thread used to restablish connection so the other threads aren't starved while waiting to re-establish connection -->
<!-- client-mode - Automatically re-establishes the connection if lost -->
<ip:tcp-outbound-channel-adapter id="outAdapter.client"
order="2"
channel="input"
client-mode="true"
connection-factory="client" /> <!-- Collaborator -->
<!-- Also send a copy to the custom aggregator for correlation and
so this message's replyChannel will be transferred to the
aggregated message.
The order ensures this gets to the aggregator first -->
<bridge input-channel="input" output-channel="toAggregator.client"
order="1"/>
<!-- Asynch receive reply -->
<ip:tcp-inbound-channel-adapter id="inAdapter.client"
channel="toAggregator.client"
connection-factory="client" /> <!-- Collaborator -->
<!-- dataType attribute invokes the conversion service, if necessary -->
<channel id="toAggregator.client" datatype="java.lang.String" />
<aggregator input-channel="toAggregator.client"
output-channel="toTransformer.client"
correlation-strategy-expression="payload.substring(0,3)"
release-strategy-expression="size() == 2"
expire-groups-upon-completion="true" />
<transformer input-channel="toTransformer.client"
expression="payload.get(1)"/> <!-- The response is always second -->
<task:scheduler id="reconnectScheduler" pool-size="10"/>
And the code used to test:
TaskExecutor executor = new SimpleAsyncTaskExecutor();
final CountDownLatch latch = new CountDownLatch(100);
final Set<Integer> results = new HashSet<Integer>();
for (int i = 100; i < 1050; i++) {
results.add(i);
final int j = i;
executor.execute(new Runnable() {
public void run() {
String result = gateway.send(j + "Hello world!"); // first 3 bytes is correlationid
System.out.println("Test Result: " + result);
results.remove(j);
latch.countDown();
}});
}
I haven't figured out entirely why you are getting that exception, but there are several problems with your test.
The countdown latch needs to be initialized at 950
Since you are exceeding 999, we need to change the correlation:
payload.substring(0,4)
With those changes, it works for me.
I'll try to figure out why we're getting that exception when I get a bit more time.
EDIT
The issue is indeed caused by the conflicting correlation ids.
The last 50 messages all have correlation id 100 which means messages are released in an indeterminate fashion (given the release is based on size). In some cases two input messages are released (causing the wrong reply to the test case). When 2 replies are released; there is no output channel.

NServiceBus 4 with Azure Storage getting NullReferenceException in TimeoutPersister

I am trying to use NServiceBus (version 4.6.0.0) with an ASP.NET MVC application hosted in a Windows Azure Website and Azure Storage for persistence but am having problems with the TimeoutManager.
Before trying to use Azure I got my app working with NServiceBus using the default MSMQ and RavenDB settings and then changed over to using Azure Storage. With that setup however I am getting multiple NullReferenceException errors right after startup in NServiceBus.Azure.TimoutManagerPersister.TryGetLastSuccessfulRead().
I have tried running this local using the Storage Emulator and with everything deployed to Azure and have the same error on both.
Here is how I have NServiceBus setup in my app:
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
public static IBus Bus { get; private set; }
protected void Application_Start()
{
...
Configure.ScaleOut(s => s.UseSingleBrokerQueue());
Feature.Enable<Sagas>();
IStartableBus startableBus = Configure.With()
.DefaultBuilder()
.DefineEndpointName("MyApp.Web")
.AzureConfigurationSource()
.UseTransport<AzureStorageQueue>()
.AzureMessageQueue()
.AzureSubscriptionStorage()
.UseAzureTimeoutPersister()
.AzureSagaPersister()
.PurgeOnStartup(false)
.UnicastBus()
.LoadMessageHandlers()
.RunHandlersUnderIncomingPrincipal(false)
.Log4Net(new DebugAppender { Threshold = Level.Warn })
.RijndaelEncryptionService()
.CreateBus();
Configure.Instance.ForInstallationOn<Windows>().Install();
Bus = startableBus.Start();
}
}
Web.config
<configSections>
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
<section name="AuditConfig" type="NServiceBus.Config.AuditConfig, NServiceBus.Core" />
<section name="AzureProfileConfig" type="NServiceBus.Config.AzureProfileConfig, NServiceBus.Hosting.Azure" />
<section name="AzureSubscriptionStorageConfig" type="NServiceBus.Config.AzureSubscriptionStorageConfig, NServiceBus.Azure" />
<section name="AzureSagaPersisterConfig" type="NServiceBus.Config.AzureSagaPersisterConfig, NserviceBus.Azure" />
<section name="AzureTimeoutPersisterConfig" type="NServiceBus.Config.AzureTimeoutPersisterConfig, NserviceBus.Azure" />
</configSections>
<connectionStrings>
<add name="NServiceBus/Transport" connectionString="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey" />
</connectionStrings>
<AzureSagaPersisterConfig ConnectionString="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey" CreateSchema="true" />
<AzureTimeoutPersisterConfig ConnectionString="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey" TimeoutManagerDataTableName="TimeoutManagerData" TimeoutDataTableName="TimeoutData" />
<AzureSubscriptionStorageConfig ConnectionString="DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey" />
And here is the exception I am getting:
System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=Microsoft.Data.Services.Client
StackTrace:
at System.Data.Services.Client.UriWriter.VisitResourceSetExpression(ResourceSetExpression rse)
at System.Data.Services.Client.DataServiceALinqExpressionVisitor.Visit(Expression exp)
at System.Data.Services.Client.UriWriter.Translate(DataServiceContext context, Boolean addTrailingParens, Expression e, Uri& uri, Version& version)
at System.Data.Services.Client.DataServiceQueryProvider.Translate(Expression e)
at System.Data.Services.Client.DataServiceQuery`1.Translate()
at System.Data.Services.Client.DataServiceQuery`1.Execute()
at System.Data.Services.Client.DataServiceQuery`1.GetEnumerator()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at NServiceBus.Azure.SafeLinqExtensions.SafeFirstOrDefault[TSource](IEnumerable`1 source) in y:\BuildAgent\work\ba77a0c29cee2af1\src\NServiceBus.Azure\SafeLinqExtensions.cs:line 13
at NServiceBus.Azure.TimeoutPersister.TryGetLastSuccessfulRead(ServiceContext context, TimeoutManagerDataEntity& lastSuccessfulReadEntity) in
y:\BuildAgent\work\ba77a0c29cee2af1\src\NServiceBus.Azure\Timeout\TimeoutLogic\TimeoutPersister.cs:line 338
at NServiceBus.Azure.TimeoutPersister.GetNextChunk(DateTime startSlice, DateTime& nextTimeToRunQuery) in y:\BuildAgent\work\ba77a0c29cee2af1\src\NServiceBus.Azure\Timeout\TimeoutLogic\TimeoutPersister.cs:line 27
at NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver.Poll(Object obj) in y:\BuildAgent\work\31f8c64a6e8a2d7c\src\NServiceBus.Core\Timeout\Hosting\Windows\TimeoutPersisterReceiver.cs:line 80
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
Even with the error messages are getting added to the Azure queue and are being processed but only for a couple of minutes than the TimeoutManager stops processing and messages are not dequeued.
Sounds like something is wrong in the storage sdk that you are using, which version are you on?

WCF MaxItemsInObjectGraph setting not working

I have been getting the following error trying to access my WCF service.
'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota
Doing some research, it looks like all I need to do is update this setting to be a higher value. This is what I am trying to do, but the setting does not seem to be getting read from the configuration. I keep getting the same exception with the 65536 value in it.
I followed the instructions found at this Link, but am having no luck.
Here is what I have configured on the WCF Service's Web.Config.
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="" />
<serviceDebug includeExceptionDetailInFaults="false" />
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</serviceBehaviors>
</behaviors>
This is what is in the Client's app.config:
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior >
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</endpointBehaviors>
</behaviors>
And lastly, I have the following attribute on the WCF service itself:
[ServiceBehavior(MaxItemsInObjectGraph = 2147483646, IncludeExceptionDetailInFaults = true)]
Despite the configurations above, I still get an Exception complaining about the 65536 value. Why aren't any of these settings being used by the applications? Is there something else that needs to be set somewhere?
You were on the right track!
All you had to do was add a name to the behavior
<behavior name="MyBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
And then on the end point add
<endpoint .... behaviorConfiguration="MyBehavior"/>
Had to go nuclear and update that machine.config;
Directions Here
The gist of it is to add the following to the "system.serviceModel" section.
<commonBehaviors>
<endpointBehaviors>
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</endpointBehaviors>
<serviceBehaviors>
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</serviceBehaviors>
</commonBehaviors>
I wrote a program to modify the machine configs for this, because support. It works for me, but I haven't done tons of testing.
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace FixMachineConfigBehavior
{
class Program
{
public static XElement IfNotExistsAdd(XDocument xd, XElement rootElement, string childName, XElement newChild)
{
if (rootElement.Elements(childName).Count() == 0)
{
Console.WriteLine(" adding " + childName + " node...");
rootElement.Add(newChild);
}
return rootElement.Element(childName);
}
static void Main(string[] args)
{
foreach (var file in Directory.EnumerateFiles(Environment.GetEnvironmentVariable("windir") + #"\Microsoft.NET\","machine.config",SearchOption.AllDirectories))
{
Console.WriteLine("fixing: " + file);
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
double ms = t.TotalMilliseconds;
File.Copy(file, file + "." + ms + ".bak", true);
var xd = XDocument.Load(file);
XElement i = xd.Root;
i = IfNotExistsAdd(xd, i, "system.serviceModel", new XElement("system.serviceModel"));
i = IfNotExistsAdd(xd, i, "commonBehaviors", new XElement("commonBehaviors"));
i = IfNotExistsAdd(xd, i, "endpointBehaviors", new XElement("endpointBehaviors"));
i = IfNotExistsAdd(xd, i, "dataContractSerializer", new XElement("dataContractSerializer", new XAttribute("maxItemsInObjectGraph", Int32.MaxValue)));
xd.Save(file);
}
Console.ReadLine();
}
}
}
I had the same problem and tried several options but I found the solution here:
https://msdn.microsoft.com/en-us/library/ms732038.aspx
In "Controlling the serialization process".
Adding ...
[ServiceBehavior(MaxItemsInObjectGraph=100000)]
class My Service ...
good luck
I had the same issue , There was some enums in returning class. What found out they cannot be null. Check whether you have any Enums that are to be returned.

Resources