Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
signalr / SignalR Programming in Microsoft ASP.NET.pdf
Скачиваний:
65
Добавлен:
25.05.2015
Размер:
19.23 Mб
Скачать

server: "localhost", port: 54321, password: "12345",

eventKey: "Broadcaster"

);

app.MapSignalR();

}

}

Again, this is all that we need to run our services on Redis. When we execute them, we will also see that the difference in performance compared to the other two mechanisms provided by SignalR is quite significant.

Custom backplanes

The developer community has also created some backplanes for SignalR that cover other serial technologies without out-of-the-box support, and their number is expected to increase with time. We must take into account the short age of the project and, more specifically, of scale-out mechanisms.

Obviously, in these cases, Microsoft does not provide official support, but these backplanes might be quite useful in scenarios not initially covered, such as those that use components such as NServiceBus or RabbitMQ.

If we have specific needs, nothing stops us from creating our own backplane. Although its creation is not overly complex, right now it is not very well documented and learning relies heavily on observing the code of existing adapters and trying to replicate them, adding the necessary customizations.

Very broadly speaking, the process consists of at least the following steps:

■■Creating a messaging bus inheriting from the ScaleoutMessageBus class provided by SignalR.

■■Implementing the Send() method, which will be invoked by SignalR when sending data to the backplane from the current node. In it, we should contact our bus and enter in it the messages that are received. This bus will be queried by all nodes connected to the server farm.

■■Creating a process to retrieve the messages sent from persistence and entering them into the message flow of the local node. This can be a background process, or it can be code written in the event handler that receives data from the system used for persistence.

■■At application startup, telling SignalR that the messaging bus to be used must be the class that we created earlier.

The following code shows a backplane that uses the file system as persistence. Obviously, it is pointless outside the local computer and its sole purpose is to give an example of the smallest messaging bus that would allow sharing messages between nodes within the same computer. Therefore, it must not be used in real environments.

170 Chapter 8Deploying and scaling SignalR

www.it-ebooks.info

// File: FilesystemMessageBus.cs

public class FileSystemMessageBus : ScaleoutMessageBus

{

// Uses the folder %temp%/backplane private readonly string BasePath =

Path.Combine(Path.GetTempPath(), "Backplane"); private FileSystemWatcher _watcher;

public FileSystemMessageBus(IDependencyResolver resolver, ScaleoutConfiguration configuration)

: base(resolver, configuration)

{

Open(0); // Use only one stream if (Directory.Exists(BasePath))

{

var files = new DirectoryInfo(BasePath).GetFiles(); foreach (var file in files)

{

file.Delete();

}

}

else Directory.CreateDirectory(BasePath);

_watcher = new FileSystemWatcher(BasePath, "*.txt")

{

IncludeSubdirectories = false, EnableRaisingEvents = true

};

_watcher.Created += FileCreated;

}

// Process messages sent from the backplane to the server private void FileCreated(object sender, FileSystemEventArgs e)

{

byte[] bytes; while (true)

{

try

{

bytes = File.ReadAllBytes(e.FullPath);

break;

 

}

 

catch

// The file is still in use

{

 

Thread.Sleep(10); // Let's wait for a short while

}

// and try again

}

var scaleoutMessage = ScaleoutMessage.FromBytes(bytes); ulong id;

string fileName = Path.GetFileNameWithoutExtension(e.Name); ulong.TryParse(fileName, out id);

foreach (var message in scaleoutMessage.Messages)

{

OnReceived(0, id,

new ScaleoutMessage(new[] { message }));

}

Deploying and scaling SignalRChapter 8

171

www.it-ebooks.info

}

// Send messages from the server to the backplane protected override Task Send(int streamIndex,

IList<Message> messages)

{

return Task.Factory.StartNew(() =>

{

var bytes = new ScaleoutMessage(messages).ToBytes(); var filePath = BasePath + "\\" +

DateTime.Now.Ticks + ".txt";

File.WriteAllBytes(filePath, bytes);

});

}

protected override void Dispose(bool disposing)

{

if (disposing)

{

_watcher.Dispose();

}

base.Dispose(disposing);

}

}

As you can see, sending messages to the backplane is done just with the Send() method, serializing the message to a file in the “%temp%\Backplane” folder.

To detect new messages from the backplane, we are using a FileSystemWatcher object on this same folder. When it detects new files—messages—the FileCreated() method is executed, which gets the new file, deserializes it, and enters it into the flow of messages of the current node.

To inform SignalR that it is the message bus to be used, we would just need to execute the following code during startup:

// File: Startup.cs

var bus = new Lazy<FileSystemMessageBus>(

() => new FileSystemMessageBus( GlobalHost.DependencyResolver, new ScaleoutConfiguration())

);

GlobalHost.DependencyResolver.Register(

typeof(IMessageBus),

() => (object)bus.Value

);

In Chapter 9, “Advanced topics,” we will learn what the Dependency Resolver is, and we will fully understand what we are doing with this code. For now, it will suffice to know that we are setting the object to be used internally when any component of SignalR needs to access the messaging bus.

172 Chapter 8Deploying and scaling SignalR

www.it-ebooks.info

Соседние файлы в папке signalr