C# RSClientPrint VERY large Spool
I am using ASP .Net 3.5 MVC1 with a DB2 backend. My company is trying to print Barcodes from the Microsoft SQL Server 2008 RSCLient Print GDI+ dialog box. We can't save files to a PDF and print local because this is for our Physical Inventory Application, and associates might could do bad stuff with local Barcodes (they are as good checks) so we are forced to print over HTTP and control their printing. Each store has a print server on location, but the web server is located in the corporate IT office. I believe i have to use a .jpeg because a .gif will cause the lines in the barcode to blur and not be readable by a scanning gun.
The application works fine with a few hundred tags (about 5 pages and about 5 min to finish the print spool), but it takes 2 hours to print 2000 tags (close to 300 pages about +150 MB). I ran Wireshark on the application to try and catch the packets coming back and forth, and passed the information on to networking and this was their response.
NO. Time Source Destination Protocol Info 36628 653.373235 HTTP [TCP Window Full] Continuation or non-HTTP traffic 36630 654.245430 TCP [TCP ZeroWindowProbe] http > 35503 [ACK] Seq=26291213 Ack=3730 Win=63137 Len=1
I digress on the back story. My question is what type of strategy can i use to help speed up the print spool over HTTP. Should i "chop" the print spool off at X pages and re spool the rest? Should i change my printing algorithm? What would be a way to shrink my size of my print spool without losing the .jpeg quality? Is there and opensource or commercial alternative to RSClientPrint that will handle the business logic i need?
Now for coding goodness! If you need anything else please let me know!
[AcceptVerbs(HttpVerbs.Post)]
[Authorization(Roles = Roles.NonInquiry)]
public ActionResult ReprintLabels(int eventId, int areaCode, int lowerLabelNumber, int upperLabelNumber)
{
if (!_eventAreaService.IsAreaEditable(eventId, areaCode))
return RedirectToAction("Index", new { eventId = eventId });
var printContext = _eventAreaService.ReprintLabels(eventId, areaCode, lowerLabelNumber, upperLabelNumber);
ActionResult result = RedirectToAction("Index", new { eventId = eventId });
if (printContext != null)
{
var redirectUrl = Url.RouteUrl(new { controller = "EventArea", action = "Index", eventId = eventId });
Session[PrintContextViewModel.SessionKey] = new PrintContextViewModel(printContext, redirectUrl);
result = RedirectToAction("PrintLabels", "LabelPrint");
}
return result;
}
public InventoryAreaPrintContext ReprintLabels(int eventId, int areaCode, int lowerLabelBound, int upperLabelBound)
{
var user = _authentication.CurrentUser;
if (user.IsInRole(Roles.CorporateInquiry) || user.IsInRole(Roles.StoreInquiry))
throw new InvalidOperationException("User must be a non-inquiry role.");
List<Fixture> fixturesToVoid = GetLabelsInRange(eventId, areaCode, lowerLabelBound, upperLabelBound).Where(f => f.StatusCode == FixtureStatus.Ready).ToList();
if (fixturesToVoid.Count < 1) return null;
// Void all old labels and tally the labels that to be recreated
// for each area involved.
var voidFixturesByArea = new Dictionary<int, int>();
foreach (var f in fixturesToVoid)
{
if (!voidFixturesByArea.ContainsKey(f.AreaCode))
voidFixturesByArea[f.AreaCode] = 1;
else
voidFixturesByArea[f.AreaCode]++;
f.StatusCode = FixtureStatus.VoidReplace;
_fixtureRepo.Update(f);
}
var storeEvent = _storeEventRepository.FindEvent(user.DefaultStore, eventId);
var lastUsedLabel = storeEvent.LastUsedLabelNumber;
var affectedAreas = new List<InventoryArea>();
// Create new labels for the affected areas.
foreach (var pair in voidFixturesByArea)
{
var area = _areaRepo.FindByKey(user.DefaultStore.GroupCode, user.DefaultStore.ID, eventId, pair.Key);
var fixtures = _fixtureBuilder.AddFixtures(lastUsedLabel.Value, area, pair.Value);
fixtures.ForEach(f => _fixtureRepo.Insert(f));
area.Fixtures = fixtures;
affectedAreas.Add(area);
}
// Update the store event counts.
var numberOfLabels = fixturesToVoid.Count();
storeEvent.LastUsedLabelNumber += numberOfL开发者_Go百科abels;
_storeEventRepository.Update(storeEvent);
return new InventoryAreaPrintContext(_barcodeGenerator) { InventoryAreas = affectedAreas, StoreEvent = storeEvent, Store = user.DefaultStore };
}
public class BarcodeGenerator : IBarcodeGenerator
{
private readonly BarCodeImage.CodeSetEncoder _codeSetEncoder;
public BarcodeGenerator(BarCodeImage.CodeSetEncoder codeSetEncoder)
{
_codeSetEncoder = codeSetEncoder;
}
public byte[] CreateBarcode(string barcodeText)
{
byte[] data;
var generator = new BarCodeImage(barcodeText, _codeSetEncoder, true)
{
InsetText = false,
Font = new Font(
FontFamily.GenericSansSerif,
10,
FontStyle.Regular,
GraphicsUnit.Pixel)
};
/**
* Keep the image dimensions at the same ratio as they will be displayed in the report.
* Currently the report is set to a height to width ratio of 1/5 so we set the image
* height to width at 1/5 as well. Otherwise the barcode will not scan properly.
**/
using (var image = generator.Render(50, 250))
using (var ms = new MemoryStream())
{
image.Save(ms, ImageFormat.Jpeg);
data = ms.GetBuffer();
}
return data;
}
}
Something was fishy in sending the image wrapper to the print spooler. What i wound up doing was to use iTextSharp's barcode 128 class and basically build the barcode out of a font instead of an image, then for human readable text i just passed in my barcode object's fixture tag string and set that value to a value on my .RDLC report. If anyone wants any code please feel free to PM me.
精彩评论