I'll start with "News from the fields."
Updates in .NET Core 1.0.1 update released. The main thing for me was Access violation on Windows - coreclr 6460:
In Jitstartup, JIT creates a file descriptor for stdout and unconditionally, without checking for failures. This happens at . Failure to check for invalid mode.
Because of this error, an exception was thrown when calling the static .Net method in a 64-bit 1C client.
Unhandled exception at 0x00007FFD76FB8528 (ucrtbase.dll) in 1cv8.exe: An invalid parameter was passed to a function for which invalid parameters cause a fatal error.
Now they have repaired and the code is perfectly executed under the 64-bit client on 8.3.9. In the examples, I replaced the .NET Core libraries with 1.0.1. I wanted to write about SignalR, but for now you can only write a server on .Net Core -
ASP.NET Core SignalR for Windows 10 UWP Appaspnet / SignalR-ServerNo customer yet. In WCF, only the client is under the Web service. ServiceHost not. There is a third-party solution.
NET core cross platform remote service invocation')
But I decided to write a solution from my 8-year-old experience for TCP / IP data exchange between TSD on Win CE and 1C for another 7-ki. Of course, you can exchange with 1C via Web services, but there are tasks where you need to interact with the operator to select data, take data prepared on the client, print to a mobile printer.
The main problems associated with networks with poor connectivity in warehouses. Therefore, it was necessary to reduce traffic due to data compression. So, when working in terminal sessions, there were problems with probing ports in slow networks - The
printing of a check for a fiscal recorder through RDP is inhibited .
There were also problems reading a two-dimensional bar code. Slow printing from a terminal server. To solve these problems, a local 1C was installed on the client’s machine, which worked as a client and server. Data from scanners were sent to a terminal server and processed there. To print to the fiscal registrar, data were sent from the server via TCP / IP and a receipt was printed from the local 1C. When printing labels from the server, the data was sent, on the basis of which a document was formed on the local 1C and sent to print.
In addition, there are no drivers for much Linux hardware. Using virtualization, you can keep Linux and Windows on the same machine, read data to Windows and share it with Linux over TCP / IP.
Now there are many who have TSD under WinCe, WinMo (they recently offered work on setting up an exchange for them). In addition, you can use TSD on other axes using UWP and Xamarin.
In addition, you can exchange messages between clients 1C, like chat.
In large .Net, I often use TCp / IP exchange
Using .NET assemblies in 1C 7.xb 8.x. Creating an external component.Using TSD on WM 6 as a wireless scanner with data acquisition from 1CSo I decided to write the same exchange, but on .Net Core and add a new approach.
Net 1C nicknames can skip the enemy code and go to the native at the end of the article how to use this component.
It was necessary to create a class for exchanging messages with compressed data. For sending data the method was used:
On the side of 1C adopted such a class
The module for the formation of messages that was written 8 years ago with a few changes.
Even then, I was using Ruslish with might and main.
Lot of codepublic class ToShare Exchange
{
public static readonly Encoding CurrentEncoder; // = Encoding.GetEcry (1251);
static toSharingPTSP ()
{
// Here is the feature of .Net Core
// Need to register provider
// and set it up according to “System.Text.Encoding.CodePages”
Encoding.RegisterProvider (CodePagesEncodingProvider.Instance);
// CurrentEncoder = Encoding.GetEncoding ("windows-1251");
// Since we are using Ruslish, we use encoding 1251.
CurrentEncoder = Encoding.GetEncoding (1251);
}
public static byte [] ExpandData (byte [] an array of DataFor a Team)
{
var memStream = new MemoryStream (array of data for a command);
var DecompressStream = new MemoryStream ();
using (GZipStream gzipStream = new GZipStream (memStream, CompressionMode.Decompress, false))
{
Byte [] buffer = new Byte [1 << 16];
int h;
while ((h = gzipStream.Read (buffer, 0, buffer.Length))> 0)
{
DecompressStream.Write (buffer, 0, h);
}
}
return DecompressStream.ToArray ();
}
//
public static byte [] CompressData (byte [] Value)
{
var memStream = new MemoryStream ();
memStream.Position = 0;
using (GZipStream gzipStream = new GZipStream (memStream, CompressionMode.Compress))
{
gzipStream.Write (Value, 0, Value.Length);
gzipStream.Flush ();
}
return memStream.ToArray ();
}
// Classic read from NetworkStream knowing the size of the data received
private static byte [] ArrayBytovIzStrim (NetworkStream stream, int size of Array)
{
byte [] result = new byte [Size of array];
int number of Characters read = 0;
while (array size> number of counted characters)
{
Number of CountedCharacters + = Stream. Read (result, Number of CountedCharacters, Size of Array - Number of CountedCharacters);
}
return result;
}
public static void RecordBit arrayVStream (NetworkStream stream, byte [] Array)
{
stream.Write (Array, 0, Array.Length);
}
// Read 1 byte from the stream and convert to bool
public static bool ReadBool (NetworkStream stream)
{
return BitConverter.ToBoolean (Massive ByteString (stream, 1), 0);
}
// Convert bool to 1 byte and write to stream
public static void Write (NetworkStream stream, bool Value)
{
Write a Massive ByteStream (stream, BitConverter.GetBytes (Value));
}
// Read 4 bytes from the stream and convert to int
public static Int32 ReadInt32 (NetworkStream stream)
{
return BitConverter.ToInt32 (Massive ByteString (stream, 4), 0);
}
// Convert int to 4 bytes and write to stream
public static void Write (NetworkStream Stream, Int32 Value)
{
Write a Massive ByteStream (stream, BitConverter.GetBytes (Value));
}
// Read the string. First comes the size of the data int
// then read the data and get the string using encoding 1251
public static string ReadString (NetworkStream stream)
{
int Size of Data = ReadInt32 (stream);
if (Size of Data == 0) return "";
return CurrentEncoder.GetString (Massive Bytes from Stream (stream, Data Size));
}
// Write the string. First, write the size of the string, then convert to byte [] using encoding 1251.
public static void Write (NetworkStream stream, string Value)
{
if (Value.Length == 0)
{
Write (stream, 0);
return;
}
byte [] result = CurrentEncoder.GetBytes (Value);
Write (stream, result.Length);
Record a Massive Byte Stream (stream, result);
}
// See WriteCompressedString is an inverse operation.
public static string ReadCompressedString (NetworkStream stream)
{
// int Size of Data = ReadInt32 (stream);
// return CurrentEncoder.GetString (ArrayBytHizStream (stream, Data Size));
bool This is a Compressed Line = ReadBool (stream);
if (! This is a Compressed String) return ReadString (stream);
int SizeDataTelements = BitConverter.ToInt32 (Massive BytesStream (stream, 4), 0);
byte [] array of data for a command = array of bytes from a stream (stream, size of data for a command);
DatasetDataCommand = ExpandData (DatasetDataCommand);
return CurrentEncoder.GetString (data array for a command);
}
// Trying to compress the GZIP string. If the size of the compressed data is less than the original, then we write the compressed data.
// otherwise original
// Write the data in the following sequence
// bool data compression flag
// int data size
// byte [] data
public static void WriteCompressedString (NetworkStream stream, string Value)
{
if (Value.Length == 0)
{
Write (false);
Write (stream, 0);
return;
}
byte [] result = CurrentEncoder.GetBytes (Value);
var CompressedData = CompressData (result);
if (result.Length> CompressedData.Length)
{
Write (true);
Write (stream, CompressedDanned.Length);
Record a Massive Byte Stream (Stream, Compressed Data);
}
else
{
Write (false);
Write (stream, result.Length);
Record a Massive Byte Stream (stream, result);
}
}
// Send data to the server
// string Command name of the method that will process the data
// string Data For a Team this is serialized data as a string
// bool There isAnswer sign of the function or procedure of the data processing method
public static void SendCommand (NetworkStream strim, string Command, string DataFor the Team, bool YesReply)
{
Write (strim, there is an answer);
Write (strim, command);
WriteCompressedString (strim, data for a command);
}
// Read data from the client
public static Message Structure Accept Command (NetworkStream strim)
{
bool YesReply = ReadBool (strim);
string Command = ReadString (strim);
string DataForCommands = ReadCompressedString (strim);
return new Message Structure (Command, Command Information, There Is An Answer);
}
}
A class is created on the server to listen to:
Everything is quite simple. When connecting, read the data, create an object to send to 1C. We start the new listener.
Sending is done on bare sockets can be viewed in the source code.
Simplified, it looks like this:
IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Parse(), );
Here is how it is processed in 1C:
The response is transmitted through the received object:
.();
By default, the event queue in 1C is 1. Therefore, 1 task can be executed, and another one to wait in the queue.
Since you can work with several devices, you need to set the desired queue size through:
.( ));
Which returns the current queue size.
Of course, you can run several 1C applications and start a TCP / IP server under different ports. but in practice, the operators are confused. The simpler for them, the better.
Methods are used to set the delegates you need.
.(,"1"); .(,"1");
Depending on the type of delegate, the desired delegate is set:
if (ReturnType == typeof(Action<string, string, object>)) return new Action<string, string, object>(); if (ReturnType == typeof(Action<string, string, string>)) return new Action<string, string, string>(AutoWrap.1);
Of course, you can use events and dynamic compilation, see the publication
“Development → 1C, .Net Core. Dynamic compilation of a wrapper class for receiving events of a .Net object in 1C " .
But once we write under 1C, it is easier to declare delegates of the desired type, and install from 1C.
For the test, you need to use 3 1C clients and call TestTopPCPIP.epf to check the event queue in 1C.
Sources can be downloaded
here .